Managing application configuration and meta-data could not get any easier.

Every application needs some way to configure itself so that it may interact with a given environment, whether it is customizing the title bar captions for a specific client or setting database connection strings for a development environment. For the simplest of applications, the app.config or machine.config probably meets your needs. For complex applications where security, scalability, and deployment also have to be addressed, you may need something a bit more robust, secure, and scalable. Enter the Configuration Management Application Block.

Once you have determined what data to store and how to store it, you must determine where to store it.

Most applications require some sort of configuration data, whether it is a file resource, a database connection string, user settings, a Web service URL, or simply organizational branding requirements. To address these issues prior to .NET, developers had to utilize some type of ASCII file such as an ini file, or they could use the Windows registry. Today with .NET, application configuration data can be stored in a specialized XML file called a configuration file.

Every .NET application has two configuration files that it uses for its settings. One is called the machine.config file and the other is called the app.config file for Windows applications or a web.config file for Web applications. The machine.config file stores configuration data at the machine level, applying the configuration data to all applications running on that particular computer. The application configuration file stores configuration data at the application level and the configuration data only applies to the specific application for which it was created.

Using the .NET machine or application configuration files is an improvement from having to roll out your own mechanism for reading configuration data, but it has some drawbacks.

  • The machine and application configuration files are read only, which makes storing configuration data in the .NET configuration files at run time impossible.
  • When storing data in the configuration file, perhaps environment-specific settings such as database connection strings, the configuration file has to be deployed to all computers requiring the application. This can be an issue when an application is promoted from a development environment to production with new configuration data. It is possible to mistype new settings into the .NET configuration file.
  • Security can be a critical issue in some environments. The configuration file is an XML document that can be read by anyone who has access to it. For Web applications, this is more difficult because ASP.NET prevents browsing the web.config file. However, with a Windows application configuration file, if a user has access to the executable, the user also has access to the configuration file.

To address these issues, you can always roll your own solution, but that can be time consuming, and you probably will have to do a lot of refactoring as your needs grow. The other way to solve these issues is to find some implementation on the Web and tweak it to meet your needs. Microsoft, through its practices and patterns group, has created just such an implementation, called the Configuration Management Application Block or CMAB for short, which addresses the above-mentioned concerns and more.

The Concept and Design of the CMAB

The CMAB addresses the needs of storing and retrieving application configuration data by creating a simple, consistent, extensible interface, including:

  • A flexible data model, allowing storage of simple name-value pairs or complex hierarchal data such as an XML fragment of user preference data. This flexible representation of configuration data is handled by the Configuration Section Handler or CSH interface.
  • An ability to write to any data store via the Configuration Storage Provider or CSP interface. This gives you the ability to store data as an XML file in a database of your choice, or anything else you can think of.
  • A mechanism to handle security and data integrity. Storing data, such as a connection string in an XML file, can at times be less than ideal. The Data Protection Provider, or DPP interface, provides mechanisms for signing the stored configuration data and encrypting it, helping to ensure that your data is not viewed or edited by unauthorized eyes.
  • An option to cache the data stored by any CSP. With some CSP implementations, it can also refresh the cache when the data changes.

The CMAB provides pre-built implementations of the Configuration Section Handler (CSH), Configuration Storage Provider (CSP), and Data Protection Provider (DPP). You can use these as is, tweak them to meet your specific needs, or create your own implementation from scratch.

Using the CMAB

With the high extensibility of the CMAB, some up-front legwork must be done to insure a successful implementation. This is true for any new component you add to an existing or new application.

Planning

The first step is defining what the application is that you are building. During this design phase, you need to determine what application data should be configurable. A good rule of thumb is that any data that can be affected by the application's environment?such as network infrastructure, geographical location, external resources, and so forth?should be considered configurable data, and be stored in a central location.

The extensible design of the Configuration Management Application Block allows the creation of new components that plug right in.

The next step is to determine how to store the data. CMAB provides two mechanisms for storing configuration data, listed in Table 1. Once you have determined what data to store and how to store it, you must determine where to store it. Should the configuration data be stored in one central location or multiple locations? Should it be easily modifiable or should the data be encrypted? See Table 2 for the Data Storage Providers in CMAB.

Getting Set Up

Now that you know what data to store, where to store it, and how it will be stored, you can start implementing the CMAB in your project. First, the CMAB must be compiled before you can add the necessary assembly references that you will need.

Once you have downloaded and installed CMAB, the default location for the code to compile it can be found in the C:\Program Files\Microsoft Application Blocks for .NET\Configuration Management\Code folder. There is a version for Visual Basic .NET in the VB folder and a C# version in the CS folder. Pick the language of your choice and select the appropriate Microsoft.ApplicationBlocks.ConfigurationManagment solution. You will also find three QuickStart sample solutions in the same folder.

Once the solution is selected and opened in Visual Studio .NET, compile the solution and you're ready to go. The two core CMAB assemblies that need to be referenced in your application are the Microsoft.ApplicationBlocks.ConfigurationManagement.dll, and the Microsoft.ApplicationBlocks.ConfigurationManagement.Interfaces.dll (see Figure 1). These assemblies can be found in the output folder of the specific language solution you used to compile the CMAB. One important thing to note is that if you plan to use the SqlStorage Storage Provider, you must also add Microsoft.ApplicationBlocks.Data.dll as an assembly reference to your application project.

![Figure 1. Use the Add Reference screen to set up the assembly references to use the CMAB](https://codemag.com/Article/Image/0505061/Figure 1.TIF)

With the necessary assembly references added to your project, it is time to dig into the application configuration file and add some entries to it. In Figure 2, you can see an example of a configuration file. The two main things you will have to do are add two custom configuration declarations XML elements to the <configSections> element and create a new Custom Configuration Section XML element.

![Figure 2. This Hashtable configuration example uses a separate XML file to store the configuration data and utilizes the refreshOnChange event.](https://codemag.com/Article/Image/0505061/Figure 2.TIF)

If your application is a Windows application, make sure an app.config file already exists; for a Web application or Web service, the web.config file is already created for you.

At the top of the config file, look for an element named <configSections> within the <configuration> element. If the <configSections> is not present in your application configuration file, add it in.

Next, add a child XML element to the <configSections> element. This element needs to be named <section>. The <section> element has two attributes?name and type. The name attribute contains the custom section name used to define the different configuration section handlers and which configuration storage provider to use with them. For now, you can make the value of the name attribute applicationConfigurationManagement.

Make the value of the type attribute Microsoft.ApplicationBlocks.ConfigurationManagement.ConfigurationManagerSectionHandler,Microsoft.ApplicationBlocks.ConfigurationManagement,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null. (Note that there are no spaces or breaks, and it all goes on one line.)

Now that the applicationConfigurationManagement section element is created, the second <section> element to be created within the <configSections> must be added. The second element allows the CMAB to determine which configuration section handler to use. The second <section> XML element, like the first, has both a name and a type attribute.

For the purposes of this walk-through, use the CMAB built-in XML Hashtable Serializer Configuration Section Handler so the value attribute is Microsoft.ApplicationBlocks.ConfigurationManagement.XmlHashtableSectionHandler,Microsoft.ApplicationBlocks.ConfigurationManagement,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null and the name attribute is myConfig. See Table 1 for a listing of the Configuration Section Handlers (CSH) included with CMAB.

Now that the custom configuration declarations have been added, the next step is to add the custom configuration section. Again looking at Figure 2, you can see the custom configuration section <applicationConfigurationManagement>. Notice that the element name matches the first custom configuration declaration section's attribute name; this is because the custom configuration declaration section defines a class and assembly used to parse the specified custom configuration section.

Add the <applicationConfigurationManagement> XML element to the <configuration> XML element. Next, add a new XML element called <configSection> with an attribute called name. The value of the name attribute should correspond with the name attribute in the custom configuration declaration section element that defines which configuration section handler to use.

How many times has the Configuration Settings Fairy changed production settings without your knowledge?

Looking at the application configuration file in Listing 1, the value is myConfig. The <configSection> element can have up to three child XML elements:

  • The <configCache> that handles the caching settings
  • The <configProvider> that handles the settings for the Configuration Storage Provider (CSP)
  • The <protectionProvider> that handles the settings for the Data Protection Provider (DPP)

The <configCache> element contains two attributes: one called enabled that can be set to true or false, and the other called refresh. For more details on how to set the refresh attribute's value, look at the section labeled Caching Data later in this article. The example application configuration file in Listing 1 has the cache feature enabled and set to refresh every 15 minutes.

The <configProvider> element, the only required element, defines the data storage provider to use as well as any necessary attributes required by the specific storage provider. Therefore, if the configuration storage provider used a database, you would probably have an attribute to specify a connection string to connect to the database. Table 2 contains a list of the configuration data providers included with the CMAB. Table 3 contains a listing of the configuration storage providers and the corresponding attributes.

The <protectionProvider> element specifies a data protection provider that can be used for signing and encrypting the stored configuration data. The CMAB comes with two DPPs. They are listed in Table 4. You can find the attributes for these two included DPPs Table 5.

Reading Data

There are two overloaded Read methods. The first method accepts a string parameter that defines the section name you want to use. The section name defines which CSH and CSP will be used for retrieving the configuration data.

In Figure 2, the name attribute in the **configSection **and **section **elements are the same, thus passing in myConfig to the Read method will tell the configuration manager to use the XML Hashtable Configuration Section Handler, and the XML File Storage data provider for retrieving the configuration data.

public object GetAllSettings(
   string sectionName)
{
   return ConfigurationManager.Read(
      sectionName);
}

It is possible to have multiple section handlers and data providers used within the same application just by specifying them in the application configuration file.

The second overloaded Read method accepts no parameters, and it uses the **defaultSection **attribute of the **applicationConfigurationManagement **element to define which CSP and CSH to use. One very important thing to note is that the Read method that uses the **defaultSection **can only be used with Hashtables. If you want to use some other object other than a Hashtable, the Read method must be called with the **sectionName **parameter.

public object GetMySetting(string key)
{
   Hashtable configData = 
      ConfigurationManager.Read();

      return configData[key];
}

Writing Data

Writing data to the CSP is just about as easy as reading it. There are two overloaded Write methods. The first overload accepts a section name and an object representing your configuration data and the second overload, using the defaultSection attribute, only accepts the object representing your configuration data. Again, the same Hashtable-only rule applies when using the write method overload without a parameter as its counterpart Read method.

public void SaveAllSettings(string sectionName, 
   object data)
{
   ConfigurationManager.Write(sectionName, data);
}

Caching Data

For almost every application, performance can be a concern. The CMAB offers a solution by providing in-memory caching functionality. The caching is really handy when dealing with settings that change rarely.

With some CSPs, such as the included XmlFileStorage provider, an event can be raised within the CMAB to refresh the in-memory cache from the CSP. To use the CMAB caching, a **configCache **element must be added to the configSection element in your application's .NET configuration file, and two attributes, **enabled **and **refresh, **must be set. The enabled attribute can be set to true or false, allowing caching to be turned on or off. The refresh attribute uses extended format notation.

The extended format consists of five values separated by spaces. These values can consist of an asterisk (*) to represent all possible numbers, a single number to indicate a single value, or a comma-separated list of numbers that can indicate multiple values. The five separate values are as follows, in this exact order: minutes, hours, day of month, month, day of week. Here are some examples of possible different settings

  • 1 * * * *: The cache expires every hour, at 1 minute past the hour.
  • 0,15,30,45 * * * *: The cache expires every 15 minutes for an hour.
  • 0 0,12 * * *: The cache expires at noon and at midnight every day.
  • 0 0 * * 1,2,3,4,5: The cache expires at midnight only on weekdays.
  • 0 12 5 * 0: The cache expires at noon on the first Sunday after the 5th day of every month.

Getting Underneath the Hood

The extensible design of the CMAB allows the creation of new components that plug right in. This extensibility is provided by interfaces. In order to create a new component for the CMAB, inherit from the specific interface for the component being targeted and implement it.

The CSH Interface

The CSH uses the **IConfigurationSectionHandler **interface in the .NET System.Configuration namespace for reading data and provides a new interface, IConfigurationSectionHandlerWriter, for writing data. The IConfigurationSectionHandler is used to simplify the implementation for storing read-only configuration data in the application or machine configuration files. Providing this ability allows you to use the exact same implementation whether you want to use the standard .NET configuration files or an external data source to store configuration data.

One very important thing to note is that the Read method that uses the defaultSection can only be used with Hashtables.

The IConfigurationSectionHandler uses the **Create **method to deserialize an XML node into an object. It's up to you to provide the implementation to deserialize the data in much the same way you would when using the IConfigurationSectionHandler.Create method with the .NET configuration files.

The IConfigurationSectionHandlerWriter inherits from IConfigurationSectionHandler and provides a new method that needs to be implemented, called Serialize. This is where you will implement the serialization of your object into an XML node.

Configuration Section Provider Interface

The CSP interfaces provide the means to actually read and write configuration data to and from the data storage provider whether it's a database, an XML file, or something else. The CSP interfaces consist of the **IConfigurationStorageReader **interface for read-only operations and the **IConfigurationStorageWriter **interface for read-and-write operations. It is assumed that if you are going to write data that you are also going to read it as well.

The IConfigurationStorageReader interface has four things to implement; the **Init **and **Read **methods, the **IsInitialized **property and the **ConfigChanges **event. The Init method is where you initialize your DSP whether it grabs an XML file or sets a connection to a database. The Read method returns an XmlNode from your storage provider. The IsInitialized property indicates whether or not the CSP as been initialized. If you want to support configuration change events, implement the ConfigChanges event.

The IConfigurationStorageWriter inherits from the IConfigurationStorageReader and adds a method called Write, which accepts an XmlNode as a parameter. This method is intended to save the serialized configuration data to the storage provider.

Data Protection Provider Interface

The **IDataProtection **interface provides the methods necessary to encrypt, decrypt, and sign (hash) data. The four methods that need to be implemented are Init, Encrypt, Decrypt, and ComputeHash.

The Init method initializes the DPP and sets up any necessary variables needed by the specific implementation of the DPP. The Encrypt and Decrypt methods are self-explanatory. The ComputeHash method creates a Hash signature of the data provided, which gives you the ability to prevent data from being changed outside of the CMAB. How many times has the Configuration Settings Fairy changed production settings without your knowledge? Now, at least you will know right away.

One important thing to note is that the DPP is intended to work with the CSP. Hence the CSP must support and call the DPP interfaces to utilize your DPP implementation with your configuration data.

Summary

The Configuration Management Application Block provides a simple, consistent, and robust interface for handling your application configuration data. It comes with a series of out of the box implementations that can be used right away, tweaked to perfection, or tossed out for a custom implementation that you build. Once the interfaces are implemented and configured, the CMAB's use could not be any easier or straightforward. Overall, the CMAB should be able to handle most?if not all?of your configuration data needs.

Listing 1: Sample console application configuration file

&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;configuration&gt;
   &lt;configSections&gt;
      &lt;section 
         name="applicationConfigurationManagement" 
         type="Microsoft.ApplicationBlocks.Configuration..." /&gt;

      &lt;section 
         name="myConfig"
         type="Microsoft.ApplicationBlocks.Configuration..." /&gt;

      &lt;/configSections&gt;

      &lt;myConfig&gt;
         &lt;XmlSerializableHashtable 
            xmlns:xsd="<a href="http://www.w3.org/2001/XMLSchema";>http://www.w3.org/2001/XMLSchema<;/a>"
            xmlns:xsi="<a href="http://www.w3.org/2001/XMLSchema-instance";>http://www.w3.org/2001/XMLSchema-instance<;/a>"&gt;
            &lt;Entries&gt;
               &lt;Entry&gt;
                  &lt;key xsi:type="xsd:string"&gt;foreColor&lt;/key&gt;
                  &lt;value xsi:type="xsd:string"&gt;Red&lt;/value&gt;
               &lt;/Entry&gt;
               &lt;Entry&gt;
                  &lt;key xsi:type="xsd:string"&gt;backColor&lt;/key&gt;
                  &lt;value xsi:type="xsd:string"&gt;White&lt;/value&gt;
               &lt;/Entry&gt;
               &lt;Entry&gt;
                  &lt;key xsi:type="xsd:string"&gt;font&lt;/key&gt;
                  &lt;value xsi:type="xsd:string"&gt;Arial&lt;/value&gt;
               &lt;/Entry&gt;
            &lt;/Entries&gt;
         &lt;/XmlSerializableHashtable&gt;
      &lt;/myConfig&gt;

      &lt;applicationConfigurationManagement  
         defaultSection="myConfig"&gt;
         &lt;configSection name="myConfig"&gt;
            &lt;configCache 
               enabled="true" 
               refresh="0,15,30,45 * * * *" /&gt;
            &lt;configProvider 
         assembly="Microsoft.ApplicationBlocks.Config..." 
         type="Microsoft.ApplicationBlocks.Configurat..."
         refreshOnChange="false" 
         signed="false" 
         encrypted="false" /&gt;
      &lt;/configSection&gt;
   &lt;/applicationConfigurationManagement&gt;
&lt;/configuration&gt;

Listing 2: Sample console application

using System;
using System.Collections;
using Microsoft.ApplicationBlocks.ConfigurationManagement;

namespace CoDeMagazine
{
   /// &lt;summary&gt;
   /// Summary description for SimpleExample.
   /// &lt;/summary&gt;
   class SimpleExample
   {
      /// &lt;summary&gt;
      /// The main entry point for the application.
      /// This method will output all the configuration settings 
      /// stored in the .NET configuration file to the console.
      /// &lt;/summary&gt;
      [STAThread]
      static void Main(string[] args)
      {
         Hashtable configData =
            ConfigurationManager.Read("myConfig") as Hashtable;

         Console.WriteLine(
            "Writing out current configuration settings");

         foreach(DictionaryEntry de in configData)
         {
            Console.WriteLine(de.Key.ToString() + " - " + 
               de.Value.ToString());
         }

         Console.ReadLine();
      }
   }
}

Table 1: These Configuration Section Handlers (CSH) are included in CMAB.

CSH Class ImplementationsDescription
XmlHashtableSectionHandlerImplements a class that takes a Hashtable and serializes it into XmlNode. It also takes serialized XML data and deserializes it back into a Hashtable. This is perfect for name value type data.
XmlSerializerSectionHandlerImplements a class that takes any class that supports the .NET XmlSerializer class and serializes it to an XmlNode. It also handles the deserialization back into its original class.

Table 2: These Configuration Storage Providers (CMPs) are included in CMAB.

CSP Class ImplementationsDescription
SqlStorageThe SqlStorage provider allows configuration data to be stored in a SQL Server database. The data is stored as an XML document in a text field, making it difficult to update directly. It is suggested that all updates are made through the CMAB.
XmlFileStorageThis implementation allows configuration data to be saved as an XML file that can be stored locally or on a network share.Read-only data can also be stored directly in the .NET configuration file.
RegistryStorageThe RegistryStorage implementation allows data to be stored in the Windows registry. This has the same issues with direct editing as the SqlStorage implementation, and can only apply settings to applications hosted on the local computer.

Table 3: Configuration Storage Provider attributes.

ConfigurationStorage Provider (CSP) AttributesDescription
(Common to all included storage providers)AssemblySpecifies the assembly name that contains the storage provider. (Required.)
TypeSpecifies the storage provider class inside the assembly to use. (Required.)
SignedIf set to true, the configuration data is signed and the data protection provider must be provided. (Optional.)
EncryptedIf set to true, the configuration data is encrypted and the Data Protection Provider (DPP) must be provided. (Optional.)
SqlStorageconnectionStringRegKeyPath Specifies the Windows registry path where the SQL connection string is stored. (Either this setting or connectionString is required.)
connectionStringSpecifies the SQL Connection string to use when connecting to a SQL database. (Either this setting or connectionStringRegKeyPath is required.)
getConfigSPSpecifies the stored procedure name used for returning configuration data. (Optional. Defaults to cmab_get_config.)
setConfigSPSpecifies the stored procedure name used for saving configuration data to the database. (Optional. Defaults to cmab_set_config.)
XmlFileStoragePathSpecifies the path where the configuration data XML file is stored. (Optional. Defaults to search the application configuration file for a custom configuration element that matches the specified name attribute in the CSH custom configuration declaration.)
refreshOnChangeIf set to true and when using the CMAB cache feature, any file modification made to the configuration data file refreshes the cached configuration data. (Optional.)
RegistryStorageregistryRootSpecifies the registry root of where the configuration is stored. (Required.)
registrySubKeySpecifies the registry sub key where the configuration data is stored. (Required.)

Table 4: Out of the Box Data Protection Providers (DPPs).

DPP Class ImplementationsDescription
BCLDataProtectionUtilizes the .NET Cryptography libraries to handle encryption and decryption of configuration data. Utilizing this implementation means you will have to manage encryption keys manually.
DPAPIDataProtectionThe DataProtection implementation utilizes the Win32 DPAPI or Data Protection API. This API handles the management of encryption keys for you. The encryption keys can be stored in the user key store, which, on a Windows NT domain with roaming profiles turned on, allows a user to encrypt and decrypt data on any computer on that domain. An alternative is to use the machine key store to allow anyone accessing that particular computer to encrypt and decrypt data.

Table 5: Configuration Storage Provider (CSP) attributes.

Data ProtectionProvider AttributesDescription
(Common to all included data protection providers)AssemblySpecifies the assembly name that contains the storage provider. (Required.)
TypeSpecifies the storage provider class inside the assembly to use. (Required.)
hashKeyRegistryPathSpecifies the Windows registry path where the hash key is stored. (Either this setting or hashKey is required.)
hashKeySpecifies the Hash key to use when encrypting data. (Either this setting or hashKeyRegistryPath is required.)
BCLDataProtectionsymmetricKeyRegistryPathSpecifies the Windows registry path where the symmetric key is stored. (Either this setting or symmetricKey is required.)
symmetricKeySpecifies the symmetric key to use when encrypting data. (Either this setting or symmetricKeyRegistryPath is required.)
DPAPIDataProtectionkeyStoreSpecifies the key store to use. (Optional. Defaults to use the machine key to encrypt the data.)