DataStream
LANGUAGES: C# | VB .NET | XML
ASP.NET VERSIONS: 1.0 | 1.1
Configure Your Apps
The Configuration Management Application Block provides simple, flexible, and extensible read/write access to configuration data.
By Brian Noyes
The .NET Framework provides a standard and easy to use approach to reading in configuration data for your applications through XML .config files. If your app is an ASP.NET application, the .config file is the web.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 same name as the app with a .config extension (i.e. myapp.exe.config) that resides in the same folder as the executable itself.
There are classes available in the .NET Framework that make it easy to read in key-value pairs from an appSettings section, or to create your own custom configuration sections and write classes to read in those sections as a chunk of structured data. Using these capabilities, you can avoid hard coding values that may change over time. The prototypical example of a piece of information that you need at run time, but that may change, is a connection string to the database.
However, there are many places where the built-in capabilities in .NET fall short. For one thing, the data in .config files is treated as read-only data that is stored in a plain text XML file in the application directory. What if you have runtime modifiable values you want to save back out? What if you want to protect the data you are reading and writing, by storing in a different location in the file system, in the registry, or in a database? What if you want to protect the data further by encrypting it? And probably most importantly, what if you may want to change some of these options over time without having to rebuild and re-deploy your application?
Over time, people have come up with a variety of solutions to these problems, resulting in more infrastructure code that they have to write and maintain. Microsoft has now provided a best-practices solution that addresses all these issues in the form of the Configuration Management Application Block (CMAB). This is one of the Microsoft Application Blocks for .NET available free for download through the patterns and practices group on MSDN (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 class library project that you can compile and use directly in your own apps, sample code that demonstrates the use of the block, and documentation that describes its design and use.
You'll Need to Talk to My Manager
The CMAB consists of a number of classes designed to work together to form a mini-framework for the reading and writing of configuration data from/to a variety of storage providers. Using the CMAB in your application code is simplicity itself - you make calls to the Read and Write methods of the ConfigurationManager class, passing an object that contains the data that you want to read or write. Where the data is actually stored is transparent to the calling code.
The storage location is driven by entries that you place in the application configuration (.config) file. The CMAB ships with providers for XML files (including the .config file itself or other XML files), SQL Server, and the Registry. You also use the .config file to set up mappings between types of information you will store, and the configuration section handlers that do the loading and writing of that data. Finally, you put settings in the .config file that determine whether the data is cached and/or encrypted, and if encrypted, what data protection provider to use. Although configuring the configuration management block with a configuration file may sound like some horrific circular logic, it should make sense after you see the CMAB in action. Figure 1 shows the way all the pieces of an application using the CMAB play together.
Figure 1. To use the CMAB, you call
Read or Write on the ConfigurationManager class. The CMAB uses configuration
section handlers that you usually provide to figure out how to serialize the
data. The CMAB figures out what section handlers to use based on your config
file, as well as other CMAB options such as caching and encryption. The CMAB
then uses storage providers and data protection providers to persist your data
to and from the stores.
Get Your Hands Dirty
Let's start with a simple example of using the CMAB with the minimum code required. The CMAB includes one configuration section handler that 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 read and write data as shown in Figure 2. Note that there are no specifics about where or how the data gets stored in the application code. Again, all those details are set through the application .config file.
private void btnRead_Click(object sender, System.EventArgs e)
{
// Read the value out of the hashtable by its key name
string connStr = ConfigurationManager.Items["connStr"] as string;
// Add it to the text box
txtConnStr.Text = connStr;
}
private void btnWrite_Click(object sender, 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. Reading and writing configuration data with a Hashtable is a simple matter of using the Items collection on the ConfigurationManager object. You will need to add a Microsoft.ApplicationBlocks.ConfigurationManagement statement to the beginning of the file to avoid fully qualifying the ConfigurationManager class name.
If you configure your app to use the XmlHashtableSectionHandler to read and write the data, you end up with an element like the one shown in Figure 3 in storage.
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> server=localhost;database=Northwind;trusted_connection=true
Figure 3. The XmlHashtableSectionHandler writes out the Hashtable in a serialized form to whatever storage location is configured for the app.
Where this element gets written will depend on the storage provider you have configured for the application. The storage providers get set through the configuration section in your .config file. In the case of the sample app that accompanies this article, the XmlFileStorage provider is used without specifying a separate file location, so the data is simply stored as a separate configuration section within the .config file itself. If a different storage provider were used (i.e. SQL Server or the Registry), this XML would be written out as a string to that storage location, and could potentially be encrypted if a data protection provider were specified.
In Figure 4, you can see a trimmed down version of the entire configuration file for the sample application (with type names and assemblies occluded for readability). The configMgmt named section contains the settings that drive the ConfigurationManager and supporting classes. The first thing you will see is that the defaultSection is set to MyAppSettings, which is the section we saw before that contains the actual Hashtable data. The configMgmt section is tied to the ConfigurationManagerSectionHandler in the configSections element. This is the section that the ConfigurationManager will look for to determine its behavior at run time.
type="..." refreshOnChange="true" signed="false" encrypted="false" /> ... Figure 4. The sample application .config file. The
configMgmt named section is used by the ConfigurationManager to drive the
run-time behavior of the block. The ConfigurationManagerSectionHandler will look for three
sub-elements under the named section element. The first and only required one
is the That is all there is to the minimal usage of the CMAB.
Just do your reading and writing of key-value pairs through the
ConfigurationManager class, set up a configuration section for the CMAB itself
telling it to use the XmlFileStorage provider, and one for the section that
will hold your data using the XmlHashtableSectionHandler. Note: If you are writing data to the config file like in
the download SimpleCMABUse Windows application, and you are running a debug
session in Visual Studio, you may think the CMAB is not working correctly
because any data you write out is not in your config file on the next run. This
is because if you have an app.config file as part of your project, VS .NET
copies that file down into your debug directory on every run and overwrites the
Store Custom Object Data If you really want to take advantage of the capabilities
of the CMAB, you won't just read and write key-value pairs to store all your
configuration data. Instead, you will want to store your objects as objects
without having to worry about breaking them out into atomic values that you can
stuff in key-value pairs. To do that, you'll need to do a little extra coding
and implement your own configuration section handler. The CMAB always stores data as XML. To translate your
custom objects into an XML representation, you implement a custom configuration
section handler. If you only need to read data from your configuration stores,
then you write a class that implements the IConfigurationSectionHandler
interface, which is defined in the System.Configuration namespace. This
interface has one method, Create which is called by the ConfigurationManager to
read your persisted data in XML format and return it to you as an object. In
your implementation of this method, you take the XmlNode that is passed to you
that contains the data, and do whatever needs to be done to re-hydrate it into
an instance of the object that it represents. The simplest way to do this is to
make sure that the XML that gets stored in the configuration store is in an XML
serialized 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. The
Create method of the IConfigurationSectionHandler is where you take the stored
XML 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 configuration
store, you will also need to implement the IConfigurationSectionHandlerWriter
interface, which is defined in the namespace for the CMAB interfaces. This
interface just requires a single Serialize method implementation that takes an
object as an argument and returns an XmlNode that can then be persisted to the
configuration store by the ConfigurationManager. The download code for this article contains another sample
application called CMABSample, which is a simple ASP.NET Web application that
stores links to Favorites in a configuration store (see end of article for
details). It uses the CMAB to read and write the collection of links to a
configuration store. It is set up to use the SQL Server configuration store
provided with the CMAB, and looks up the configuration string in the registry.
It also uses a custom section handler as described above to store the
collection of Favorites. See the readme in the download code for detailed
instructions on getting the sample up and running on your machine. The CMAB provides a great, easy to use, flexible, and
extensible solution to reading and writing configuration data for your apps. In
your application code, you just read and write to the ConfigurationManager.
Through your config file, you can drive where the data gets stored, whether it
is cached, whether it gets encrypted before storage, and if so, how. Unless you
have trivial read-only requirements for a few key-value pairs of data for your
apps, I recommend you look into using the CMAB as a standard part of your
applications for storing and reading configuration data. The code for this article is
available for download. Brian Noyes is a consultant, trainer, speaker, and
writer with IDesign, Inc. (http://www.idesign.net),
a .NET focused architecture and design consulting firm. Brian specializes in
designing and building data-driven distributed applications. He has more than
12 years experience in programming, engineering, and project management, and is
a contributing editor for C#PRO, asp.netPRO, and other publications. Contact
him at mailto:[email protected].