HTTPS SSH

DynamicStore

Breaking changes: DynamicStore version 0.10.* will introduce breaking changes to the project namespacing. Update your version constraints as appropriate if you want to avoid it.

DynamicStore is a dead-simple, lightweight data access library for .NET applications. It is designed to be lightweight, extensible, configurable and simple, taking the difficulty out of app data storage.

Getting Started

Installation

Install the base library from NuGet:

Install-Package DynamicStore

Now install at least one provider. For the sakes of argument, we'll use the basic JSON file option:

Install-Package DynamicStore.Providers.Local

You're ready to go!

Get to the code!

The easiest way to start with DynamicStore is to use its fluent API, like below:

var store = new DynamicStoreEngine()
            .EnableStorageProvider(new LocalFileStorageProvider())
            .UseComplexStore();

Now, your store object can be used to create and retrieve your objects quickly and easily:

var obj = store.Objects.Create(new SampleObject {Id = "complexTest", Rev = "4"});
var allObjects = store.Objects.Get<SampleObject>();
var singleObject = store.Objects.GetById("complexTest");
store.Delete(singleObject);

Yes, it really is that simple! Now keep reading for the dirty on DynamicStore's other features...

Providers

DynamicStore is built around the idea of pluggable providers. Above, we jumped for the LocalFileStorageProvider because its nice and easy to get started with. But what if you wanted to store your data in a CouchDB NoSQL Database? No problem:

Install-Package DynamicStore.Providers.CouchDB

You've just installed a provider using Daniel Wertheim's excellent MyCouch library. Now it's just a matter of slightly changing our earlier code:

var store = new DynamicStoreEngine()
            .EnableStorageProvider(new MyCouchDBProvider())
            .UseComplexStore();

Now this time, its not quite that simple. It's all well and good to store your data in CouchDB, but where? That's where configuration comes in...

Configuration

Since DynamicStore is built on the principles of pluggable providers, it would be pretty pointless to have to hard-code each provider independently anyway, wouldn't it? That's where DynamicStore's configuraiton model comes in. It's all based around a DynamicConfiguration object. Don't worry, its basically just a fancy Dictionary! Configurations are made up of key-value pairs where the key is just a name, and the value is any old object you want to throw at it. For example, here is what it takes to configure the CouchDB/MyCouch provider from above:

var conf = new DynamicConfiguration()
        {
            {
                "db:UserName", new KeyValuePair<Type, object>(typeof (string), "testuser")
            },
            {
                "db:Password", new KeyValuePair<Type, object>(typeof (string), "testpassword")
            },
            {
                "db:Uri", new KeyValuePair<Type, object>(typeof (Uri), new Uri("cloud.cloudant.com"))
            },
            {
                "db:DbName", new KeyValuePair<Type, object>(typeof (string), "myAwesomeDB")
            }
        };

That may look confusing, but you will only have to write it once. For more information on how configurations are handled, check the wiki. Now, to use it, almost the same as before, with one new statement:

    var store = new DynamicStoreEngine()
            .EnableStorageProvider(new MyCouchDBProvider())
            .AddNewConfiguration(conf)
            .UseComplexStore();

And now your data will be seamlessly stored and retrieved from any local or remote CouchDB instance. Not so bad, was it? But wait, what if you want to use multiple storage providers?

Configuration Providers

While the normal provider in DynamicStore is a storage provider, there's also special providers called Config Providers that give you the same simple client API and pluggability (sure, thats a word), but with your configuration objects. So how would you enable it? Simple:

    var store = new DynamicStoreEngine()
            .EnableStorageProvider(new MyCouchDBProvider())
            .AddNewConfiguration(conf)
            .EnableConfiguration(new LocaFileConfigProvider())
            .UseComplexStore();

and bam, your configuration will be stored behind the scenes using the same simple local file provider from earlier. But who wants a bunch of JSON files cluttering up your project?

    var store = new DynamicStoreEngine()
            .EnableStorageProvider(new MyCouchDBProvider())
            .EnableConfiguration(new AppConfigProvider())
            .UseComplexStore();

See what we did there? Cool, isn't it.

Maybe, you don't use your app.config much? No problem:

    var store = new DynamicStoreEngine()
            .EnableStorageProvider(new MyCouchDBProvider())
            .EnableConfiguration(new EnvironmentVarConfigProvider())
            .UseComplexStore();

You get the idea by now. When you first create your DynamicStore, it will automatically look up your chosen configuration provider for a config to match your chosen storage provider, configures it and gives you back your DynamicStore to start dealing with your objects.

Store Types

You may have noticed that UseComplexStore() call is always at the end of our code? That's important since that's where the store is initialized. But even that is configurable! In addition to the complex store you see here, there is a SimpleStore object that gives you a similar experience for simpler data scenarios. Most notably, the SimpleStore only supports one object type! The full-fat DynamicStore lets you pick your object type at runtime and will do its best to handle all the types in the background, but SimpleStore is created with only one type in mind. Check out the code below:

    var store = new DynamicStoreEngine()
            .EnableStorageProvider(new MyCouchDBProvider())
            .EnableConfiguration(new AppConfigProvider())
            .UseSimpleStore<SampleObject>();

Now your store object gives you really easy access to your objects:

var objects = store.Get(); //all your objects
var myObject = store.GetById("your id goes here"); //gets a single object
myObject.Name = "New Name!";
var ref = store.Update(myObject); //changes are automatically persisted by the storage provider

So, you can consider the SimpleStore a little shortcut for when you have simpler data requirements. There is one caveat to all this easy easy code...

IDynamicObject

Currently, as this project is quite new, there is a requirement in the backend logic that any objects you want to store or update via DynamicStore or SimpleStore implement the IDynamicObject interface. Don't worry, its a really simple interface:

public interface IDynamicObject
{

    string Id { get; }

    string Rev { get; set; }
}

Yep, it's mostly just to guarantee string id's so we don't have to do too much type mapping in the providers.

Available Providers

Okay, so this is a new library but a number of providers are already available

Storage

  • MyCouch/CouchDB (in DynamicStore.Providers.CouchDB)
  • Local JSON files (in DynamicStore.Providers.Local)

Configuration

  • Local JSON files (in DynamicStore.Providers.Local)
  • Environment Variables (built-in to the .NET 4.5 version)
  • app.config sections (in DynamicStore.Providers.AppConfig)

DynamicStore itself

There's actually a couple of versions of the DynamicStore library as well: - The normal .NET 4.5-and-up library - Portable Class Library (in DynamicStore.Pcl) - Universal Class Library (in DynamicStore.Universal)

NOTE: The Univeral package currently has issues with packaging thanks to a bug in NuGet 2.8.x

Credits

Massive thanks to a few projects and people: - Icons8 for the neat project icons (free no less) - Daniel Wertheim for MyCouch, and inadvertently inspiring the architecture of this project

Check out the Licence page for more.