DataStream
LANGUAGES: C# | VB .NET | XML
ASP.NETVERSIONS: 1.0 | 1.1
Configure Your Apps
The Configuration Management Application Block providessimple, flexible, and extensible read/write access to configuration data.
By Brian Noyes
The .NET Framework provides a standard and easy to useapproach to reading in configuration data for your applications through XML.config files. If your app is an ASP.NET application, the .config file is theweb.config file that resides in the application root directory or sub-folder.If your app is a Windows application, the .config file is a file with the samename as the app with a .config extension (i.e. myapp.exe.config) that residesin the same folder as the executable itself.
There are classes available in the .NET Framework thatmake it easy to read in key-value pairs from an appSettings section, or tocreate your own custom configuration sections and write classes to read inthose sections as a chunk of structured data. Using these capabilities, you canavoid hard coding values that may change over time. The prototypical example ofa piece of information that you need at run time, but that may change, is aconnection string to the database.
However, there are many places where the built-incapabilities in .NET fall short. For one thing, the data in .config files istreated as read-only data that is stored in a plain text XML file in theapplication directory. What if you have runtime modifiable values you want tosave back out? What if you want to protect the data you are reading andwriting, by storing in a different location in the file system, in theregistry, or in a database? What if you want to protect the data further byencrypting it? And probably most importantly, what if you may want to changesome of these options over time without having to rebuild and re-deploy yourapplication?
Over time, people have come up with a variety of solutionsto these problems, resulting in more infrastructure code that they have towrite and maintain. Microsoft has now provided a best-practices solution thataddresses all these issues in the form of the Configuration ManagementApplication Block (CMAB). This is one of the Microsoft Application Blocks for.NET available free for download through the patterns and practices group onMSDN (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/cmab.asp).
To use the CMAB, you first must download the code from MSDN.You can choose between C# and VB .NET implementations. What you get is a classlibrary project that you can compile and use directly in your own apps, samplecode that demonstrates the use of the block, and documentation that describesits design and use.
You'll Need to Talk to My Manager
The CMAB consists of a number of classes designed to worktogether to form a mini-framework for the reading and writing of configurationdata from/to a variety of storage providers. Using the CMAB in your applicationcode is simplicity itself - you make calls to the Read and Write methods of theConfigurationManager class, passing an object that contains the data that youwant to read or write. Where the data is actually stored is transparent to thecalling code.
The storage location is driven by entries that you placein the application configuration (.config) file. The CMAB ships with providersfor XML files (including the .config file itself or other XML files), SQLServer, and the Registry. You also use the .config file to set up mappingsbetween types of information you will store, and the configuration sectionhandlers that do the loading and writing of that data. Finally, you putsettings in the .config file that determine whether the data is cached and/or encrypted,and if encrypted, what data protection provider to use. Although configuringthe configuration management block with a configuration file may sound likesome horrific circular logic, it should make sense after you see the CMAB inaction. Figure 1 shows the way all the pieces of an application using the CMABplay together.
Figure 1. To use the CMAB, you callRead or Write on the ConfigurationManager class. The CMAB uses configurationsection handlers that you usually provide to figure out how to serialize thedata. The CMAB figures out what section handlers to use based on your configfile, as well as other CMAB options such as caching and encryption. The CMABthen uses storage providers and data protection providers to persist your datato and from the stores.
Get Your Hands Dirty
Let's start with a simple example of using the CMAB withthe minimum code required. The CMAB includes one configuration section handlerthat lets you easily read and write key-value pairs using a Hashtable object.Using that handler, you can start using the Configuration Manager class to readand write data as shown in Figure 2. Note that there are no specifics aboutwhere or how the data gets stored in the application code. Again, all thosedetails are set through the application .config file.
private void btnRead_Click(objectsender, System.EventArgs e)
{
// Read the value out of the hashtable by its key name
string connStr = ConfigurationManager.Items["connStr"] asstring;
// Add it to the text box
txtConnStr.Text = connStr;
}
private void btnWrite_Click(objectsender, System.EventArgs e)
{
// Make sure the configuration manager is initialized
Hashtable values = new Hashtable();
// Write an empty hashtable into the manager to initialize
// the storage - just needs to be done once in the app
ConfigurationManager.Write(values);
// Now write items into that storage
ConfigurationManager.Items["connStr"] = txtConnStr.Text;
}
Figure 2. Readingand writing configuration data with a Hashtable is a simple matter of using theItems collection on the ConfigurationManager object. You will need to add aMicrosoft.ApplicationBlocks.ConfigurationManagement statement to the beginningof the file to avoid fully qualifying the ConfigurationManager class name.
If you configure your app to use theXmlHashtableSectionHandler to read and write the data, you end up with anelement like the one shown in Figure 3 in storage.
<MyAppSettings>
<XmlSerializableHashtablexmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Entries>
<Entry>
<key xsi:type="xsd:string">connStr</key>
<value xsi:type="xsd:string">
server=localhost;database=Northwind;trusted_connection=true
</value>
</Entry>
</Entries>
</XmlSerializableHashtable>
</MyAppSettings>
Figure 3. TheXmlHashtableSectionHandler writes out the Hashtable in a serialized form towhatever storage location is configured for the app.
Where this element gets written will depend on the storageprovider you have configured for the application. The storage providers get setthrough the configuration section in your .config file. In the case of thesample app that accompanies this article, the XmlFileStorage provider is usedwithout specifying a separate file location, so the data is simply stored as aseparate configuration section within the .config file itself. If a differentstorage provider were used (i.e. SQL Server or the Registry), this XML would bewritten out as a string to that storage location, and could potentially beencrypted if a data protection provider were specified.
In Figure 4, you can see a trimmed down version of theentire configuration file for the sample application (with type names and assembliesoccluded for readability). The configMgmt named section contains the settingsthat drive the ConfigurationManager and supporting classes. The first thing youwill see is that the defaultSection is set to MyAppSettings, which is thesection we saw before that contains the actual Hashtable data. The configMgmtsection is tied to the ConfigurationManagerSectionHandler in the configSectionselement. This is the section that the ConfigurationManager will look for todetermine its behavior at run time.
<?xml version="1.0"encoding="utf-8" ?>
<configuration>
<configSections>
<section name="configMgmt" type="..." />
<section name="MyAppSettings" type="..." />
</configSections>
<configMgmt defaultSection="MyAppSettings">
<configSection name="MyAppSettings">
<configCache enabled="false" refresh="1 * * * *"/>
<configProvider assembly="..."
type="..." refreshOnChange="true"
signed="false" encrypted="false" />
</configSection>
</configMgmt>
<MyAppSettings>
...
</MyAppSettings>
</configuration>
Figure 4. The sample application .config file. TheconfigMgmt named section is used by the ConfigurationManager to drive therun-time behavior of the block.
The ConfigurationManagerSectionHandler will look for threesub-elements under the named section element. The first and only required oneis the <configProvider> element. This is the element that identifies thestorage provider. In the case of the sample application, the XmlFileStorageprovider is identified. The <configCache> lets you configure whether thedata read in is cached, and when that cached data should be expired. See thedocs for a full explanation of the options there. The final element that is notshown in the sample is a <protectionProvider> element under which you canconfigure encryption information for a data protection provider that will beused when reading and writing the data.
That is all there is to the minimal usage of the CMAB.Just do your reading and writing of key-value pairs through theConfigurationManager class, set up a configuration section for the CMAB itselftelling it to use the XmlFileStorage provider, and one for the section thatwill hold your data using the XmlHashtableSectionHandler.
Note: If you are writing data to the config file like inthe download SimpleCMABUse Windows application, and you are running a debugsession in Visual Studio, you may think the CMAB is not working correctlybecause any data you write out is not in your config file on the next run. Thisis because if you have an app.config file as part of your project, VS .NETcopies that file down into your debug directory on every run and overwrites the<myapp>.exe.config file (where <myapp> is the name of your app).You'll need to inspect the contents of that file in your debug directorybetween runs to see that the changes are being written, or run outside thedebugger so that the file does not get overwritten.
Store Custom Object Data
If you really want to take advantage of the capabilitiesof the CMAB, you won't just read and write key-value pairs to store all yourconfiguration data. Instead, you will want to store your objects as objectswithout having to worry about breaking them out into atomic values that you canstuff in key-value pairs. To do that, you'll need to do a little extra codingand implement your own configuration section handler.
The CMAB always stores data as XML. To translate yourcustom objects into an XML representation, you implement a custom configurationsection handler. If you only need to read data from your configuration stores,then you write a class that implements the IConfigurationSectionHandlerinterface, which is defined in the System.Configuration namespace. Thisinterface has one method, Create which is called by the ConfigurationManager toread your persisted data in XML format and return it to you as an object. Inyour implementation of this method, you take the XmlNode that is passed to youthat contains the data, and do whatever needs to be done to re-hydrate it intoan instance of the object that it represents. The simplest way to do this is tomake sure that the XML that gets stored in the configuration store is in an XMLserialized format so that you can just deserialize it into an object instance,as shown in Figure 5.
public object Create(object parent,object configContext, XmlNode section)
{
// Get a reader to deserialize into memory,
//placing the xml fragment into it
StringReader reader = new StringReader(section.OuterXml);
// Deserialize from the string reader into an
//instance of our custom data class
return m_serializer.Deserialize(reader);
}
Figure 5. TheCreate method of the IConfigurationSectionHandler is where you take the storedXML representation of your data and convert it back into an object instance.XML serialization is the easiest way to do this.
If you also want to write data out to your configurationstore, you will also need to implement the IConfigurationSectionHandlerWriterinterface, which is defined in the namespace for the CMAB interfaces. Thisinterface just requires a single Serialize method implementation that takes anobject as an argument and returns an XmlNode that can then be persisted to theconfiguration store by the ConfigurationManager.
The download code for this article contains another sampleapplication called CMABSample, which is a simple ASP.NET Web application thatstores links to Favorites in a configuration store (see end of article fordetails). It uses the CMAB to read and write the collection of links to aconfiguration store. It is set up to use the SQL Server configuration storeprovided with the CMAB, and looks up the configuration string in the registry.It also uses a custom section handler as described above to store thecollection of Favorites. See the readme in the download code for detailedinstructions on getting the sample up and running on your machine.
The CMAB provides a great, easy to use, flexible, andextensible solution to reading and writing configuration data for your apps. Inyour application code, you just read and write to the ConfigurationManager.Through your config file, you can drive where the data gets stored, whether itis cached, whether it gets encrypted before storage, and if so, how. Unless youhave trivial read-only requirements for a few key-value pairs of data for yourapps, I recommend you look into using the CMAB as a standard part of yourapplications for storing and reading configuration data.
The code for this article isavailable for download.
Brian Noyes is a consultant, trainer, speaker, andwriter with IDesign, Inc. (http://www.idesign.net),a .NET focused architecture and design consulting firm. Brian specializes indesigning and building data-driven distributed applications. He has more than12 years experience in programming, engineering, and project management, and isa contributing editor for C#PRO, asp.netPRO, and other publications. Contacthim at mailto:brian.noyes@idesign.net.