Introduction

Recently I have been working on a task that required a lot of flexibility in storing and accessing configuration settings. I have searched the web and found plenty
of solutions and examples but none of them really satisfied my requirements. This forced me to give up the search and to consider writing my own version. Once I got to
the point that it appeared to be working, I decided to share it in case someone might find it more useful than the rest of the options out there.

Background

In order to finish the task, I had to make sure the following conditions were met in order to make it useful:

User should be able to easily change or choose how and where configuration data is stored without affecting the configurable objects.

Accessing and storing configuration should be very simple and transparent to the user but at the same time reliable.

Types of any of the child objects are not known to the process that initiates loading of configuration and child objects are created depending on specific configurations.

A potential solution came to mind when I was working on a web project and used View State to store some values between page post backs.
It reminded me that strings can represent any data including binary. They are relatively easy to use and can be stored pretty much anywhere - XML file,
database, or even binary file. And just like we operate with strings in XML, we can access and store data as strings and convert it to appropriate data types when loading.

In order to be able to manage complex configurations, I had to come up with two concepts which we’ll call context and value. Context is simply
a container that holds a collection of other contexts and values, and values are just simple string values. The loading and saving is done using two methods
that perform reading and writing configuration to the appropriate context which is similar to the IXmlSerializable interface.

Using the code

You will need to implement the IConfigurationElement interface so that class configuration can be saved and loaded. The interface is similar
to the IXmlSerializable interface and includes two methods: ReadConfiguration and WriteConfiguration.
As their names suggest, one is used to read configuration and the other to write.

Since we are dealing with strings only, we can use indexers to load and save a value. It will be the user’s responsibility to convert a string to the appropriate data type
when reading, and back when writing. For example:

Question now, what do we do if we want to save a subset of configuration values? In this case, you need to obtain a context object from the current context by ether creating
a new one or getting an existing one. For this, IConfigurationContext provides three methods: Get, GetAll, and Create.
The Get method accepts a string parameter that specifies the name of the parameter and returns a list of contexts. GetAll will return all contexts
associated with the current context and you can access the context name by using the property Name. Accordingly, the Create method will create
a new context with the provided name.

Below is an example of accessing and storing a person's name (FirstName and LastName) and postal address (MailingAddress).
The example below does not include the implementation of the PostalAddress class but it is available
in the attached source code together with other validation logic not shown here.

Now let’s look at how this can be used. For this demonstration, I created a working implementation of IConfigurationContext that uses XmlNode to store configurations.
So below is an example that should be simple enough to understand.

User should be able to easily change or choose how and where configuration data is stored without affecting the configurable objects.
We accomplished that by simply providing different implementations of IConfigurationContext. So instead of XmlConfigurationContext, we can
easily create DatabaseConfigurationContext or WebServiceContext or other variations.

Accessing and storing configuration should be very simple and transparent to the user but at the same time reliable. Accessing settings is straightforward
and simple using the simple indexer.

Types of any of the child objects are not known to the process that initiates the loading of the configuration. When loading
Person, we do not know what settings it will save nor do we care, we simply provide the context where to save or find the needed values.

About the Author

Comments and Discussions

The article was never about XML. If you need to you can create your own class that stores and reads configuration in JSON format but your classes that contain data do not have to be changed. Simply replace

var context = new XmlConfigurationContext();

with

var context = new JsonConfigurationContext();

and you have your favorite JSON formatted configuration.

1. Whatever .NET has is not flexible enough and not really the main point of the article.
2. You can create your own class that stores and reads configuration in JSON format or any other format and any source.

I completely disagree that this is a go back or that this is even similar to ini files, however I understand that the title might mislead you. This approach could be used not just for configurations but for you object model data. And yes, I do know that you can save whole object model by serializing into and deserializing from XML file. However, if you look at the post you will see that I included requirements I had to follow which are not achievable with simply serializing and deserializing. The article's point is not about just saving and loading configurations but to make it easy, straight-forward, flexible and not limited to xml only. Let me explain the issues you have to deal with when you try to save settings to xml automatically (assuming using serialization).

User should be able to easily change or choose how and where configuration data is stored without affecting the configurable objects
If you are using serialization you are restricting yourself to the XML. Now, let's assume tomorrow you decide that you want to save to the database. I know you can simply dump xml text to the database however it will not be structured and it will not be queriable. If you use my approach you simply pass another implementation of IConfigurationContext but your object model classes will not be affected.

Types of any of the child objects are not known to the process that initiates loading of configuration and child objects are created depending on specific configurations
I can understand that for storing and loading of configurations serializing is sufficient and yes, very easy with minimal coding. However this does not look so easy and reliable once you introduce plug-ins, while providing those plug-ins a reliable way to store their configurations, or any kind of dynamics into your configuration. Approach I have mentioned makes it easier for developers to create plug-ins. They do not need to care about where and how to store the configuration. Let the host application deal with the storing and managing it. In addition this allows storing different configuration settings for the same plug-in depending on the context.

Accessing and storing configuration should be very simple and transparent to the user but at the same time reliable
Now, if you manage to pull it off while successfully addressing forementioned requirements using serialization, it will most likely be neither simple nor transparent, and probably very fragile. If you need more control over serialization and deserialization you are back to dealing with XmlReader/XmlWriter which again is restricting you to Xml in addition to forcing you to use methods like MoveToElement and forcing you to ensure you are at the correct node or attribute. In my view this adds too many moving parts which in turn increases chance for the mistake.

Yeah, my bad. I originally had it as a Setting and while I was writing a post I decided that it would make more sense if I renamed the tag to "value" and apparently forgot to change the closing tag. I'll update that. Thanks.