If you've ever seen the web.config file that ASP.NET uses, and thought, "Wow, I'm so glad they configure things that way, in this nice, easy-to-use XML file. Wish I could do that!" then you should check out the System.Configuration namespace. There's an interface called IConfigurationSectionHandler that lets you write your own parsers for your application configuration file, letting you put whatever you want in there.
I've written a bunch of these over the last few months, but today I wrote the last one I ever will. Here's the code for it:
using System;
using System.Configuration ;
using System.Xml ;
using System.Xml.Serialization ;
using System.Xml.XPath ;
namespace DevelopMentor.Candera.Utilities
{
public class XmlSerializerSectionHandler :
IConfigurationSectionHandler {
public object Create(
object parent,
object configContext ,
System.Xml.XmlNode section) {
XPathNavigator nav = section.CreateNavigator ();
string typename = ( string ) nav.Evaluate ("string(@type)");
Type t = Type.GetType ( typename );
XmlSerializer ser = new XmlSerializer (t);
return ser.Deserialize ( new XmlNodeReader (section));
}
}
}
It’s very, very simple. When you map a section of your configuration file to this handler, using an entry in your config file that looks like this:
< configuration >
< configSections >
< section name =" MyStuff " t ype ="DevelopMentor.Candera.Utilities.XmlSerializerSectionHandler, Utilities"/>
</ configSections >
</ configuration >
What happens is that any time you ask for the MyStuff section of the config file with code that looks like this:
ConfigurationSettings.GetConfig (" MyStuff ");
It will actually go look in the config file to figure out who knows how to deal with the “MyStuff” section. When it sees that it’s the XmlSerializerSectionHandler, it’ll create an instance of this object and call Create, passing it (via the section parameter) a reference to the relevant portion of the config file. In our case, it might look something like this:
< configuration >
<!-- configSections element goes here -->
< MyStuff type =" SomeNamespace.MyStuff , CraigsConfig ">
< Foo > 1.234 </ Foo >
< Bar > A bunch of information </ Bar >
</ MyStuff >
</ configuration >
What my handler does is to look for the “type” attribute on this bit of XML, in the form “classname, assemblyname”. In this case, it’s a class called MyStuff in a namespace SomeNamespace. It then – and here’s the good bit – uses the XmlSerializer to initialize an instance of this type from the XML in the configuration file. The XmlSerializer is a very cool piece of the .NET libraries, and you should check it out if you haven’t already. Basically, you write a type like this:
public class MyStuff
{
private float foo ;
private string bar;
public float Foo
{
get { return foo ; }
set { foo = value ; }
}
public string Bar
{
get { return bar; }
set { bar = value ;
}
}
And the XmlSerializer takes care of turning it into the XML above and vice versa. There are even a bunch of attributes you can use to control the process.
So given the section handler I wrote, any time I want to put some information in a config file, all I have to do is write a type like MyStuff, map a section to my XmlSerializerSectionWriter, write some XML into the config file with the values I’d like to capture and then ask the infrastructure to read it like this:
MyStuff ms = ( MyStuff ) ConfigurationSettings.GetConfig (" MyStuff ");