Configuring a .NET 2.0 Application Using the ConfigurationSection class

I wanted to write a web site checker service to check to see if our web sites were responding. The service would run a check every so often by creating an HttpWebRequest object for each site, and getting an HttpWebResponse object asynchronously. If the response object reported an error, or there was a problem getting the response object, an error would be logged in the Application event log.

Writing the service was pretty trivial – I just wrote a WebSiteChecker class to move most of the code away from my implementation of the ServiceBase class, and everything worked great. But I’d hard coded my URLs. Extremely bad practice, but something that we’re all guilty of. I needed to move the URLs to the application’s configuration file and read them in from there. Having used IConfigurationSectionHandler to do this beforehand, I was surprised to find that the class had been deprecated.

Enter ConfigurationSection. This class, new to .NET 2.0, makes implementing custom configuration sections even easier – IF you know what you’re doing. To some of us, the use of attributes seems strange and mystical, and much of what you do when extending ConfigurationSection involves them.

First of all, we’re going to think about what our configuration XML is going to look like. This will appear in App.config or Web.config depending on what kind of project you’re developing. A an example, I’m going to use a section that looks like this:

  1. <alex>
  2.     <wsc interval="90000">
  3.         <eventLogInfo logName="Application" source="Web Site Checker" />
  4.         <sites>
  5.             <add name="Alex's Blog" url="http://www.alexhumphrey.me.uk" />
  6.             <add name="Mike's Blog" url="http://www.michael-lomas.co.uk" />
  7.             <add name="Hutchy's Blog" url="http://www.hutchy.co.uk" />
  8.         </sites>
  9.     </wsc>
  10. </alex>

Looking above, <alex> is the section group name, <wsc> is the section itself, it has a property called interval, representing the number of milliseconds between each check. Within wsc, we have <eventLogInfo> which has an event source, and the name of the system event log to write to. Then we have a collection called <sites>, with urls in it. Now we need to think about the classes we need to create.

We need classes to represent each element in the section. We’ll start at the top, <alex> doesn’t need a class, it’s just a section group. <wsc> however does. It’s a configuration section, so we’ll call it WscConfigurationSection. Next we have <eventLogInfo>. This is simply an element, so we’ll call it EventLogInfoElement. Next is the <sites> collection, containing just elements, so the elements themselves will become instances of UrlElements, and the collection will be a UrlElementCollection. For each of these classes, there is a class that we need to inherit from – they are as follows:

  1. WscConfigurationSection : ConfigurationSection
  2. EventLogInfoElement : ConfigurationElement
  3. UrlElementCollection : ConfigurationElementCollection
  4. UrlElement: ConfigurationElement

Please note that all of this requires the System.Configuration namespace. System.Configuration is strewn about System.dll and System.Configuration.dll, aswell as having a few classes in mscorlib.dll, so just because intellisense can see it, doesn’t mean it’s all there. In most cases, you’ll have to manually add a reference to System.Configuration by right clicking on References under your project in solution explorer. The configuration elements are the easiest to write, so we’ll start with those. All you need to do is to add the appropriate properties and decorate them with the appropriate attributes. The attribute we’ll use now is ConfigurationProperty, and it describes the name of the xml attribute to look at.

  1. public class EventLogInfoElement : ConfigurationElement
  2. {
  3.     [ConfigurationProperty("logName")]
  4.     public string LogName
  5.     {
  6.         get{return (string)this["logName"];}
  7.         set{this["logName"] = value;}
  8.     }
  9.  
  10.     [ConfigurationProperty("source")]
  11.     public string EventSource
  12.     {
  13.         get{return (string)this["source"];}
  14.         set{this["source"] = value;}
  15.     }
  16. }
  17.  
  18. public class UrlElement : ConfigurationElement
  19. {
  20.     [ConfigurationProperty("name")]
  21.     public string Name
  22.     {
  23.         get{return (string)this["name"];}
  24.         set{this["name"] = value;}
  25.     }
  26.  
  27.     [ConfigurationProperty("url")]
  28.     public string Url
  29.     {
  30.         get{return (string)this["url"];}
  31.         set{this["url"] = value;}
  32.     }
  33. }

 

There, those are our elements, just the collection and the section to go. ConfigurationElementCollection has a load of methods that you can override, but for this example, we’ll keep it to the bare minumum, implementing only abstract members:

  1. public class UrlElementCollection : ConfigurationElementCollection
  2. {
  3.     public UrlElement this[int index]
  4.     {
  5.         get
  6.         {
  7.             return (UrlElement)BaseGet(index);
  8.         }
  9.         set
  10.         {
  11.             if (BaseGet(index) != null)
  12.             {
  13.                 BaseRemoveAt(index);
  14.             }
  15.  
  16.             BaseAdd(index, value);
  17.         }
  18.     }
  19.  
  20.     protected override ConfigurationElement CreateNewElement()
  21.     {
  22.         return new UrlElement();
  23.     }
  24.  
  25.     protected override object
  26.         GetElementKey(ConfigurationElement element)
  27.     {
  28.         return ((UrlElement)element).Name;
  29.     }
  30. }

OK, the only thing left is to bring it all together with our WscConfigurationSection. Here we’ll introduce the ConfigurationCollection attribute.

  1. public class WscConfigurationSection : ConfigurationSection
  2. {
  3.     [ConfigurationProperty("interval")]
  4.     public int PollingInterval
  5.     {
  6.         get{return (int)this["interval"];}
  7.         set{this["interval"] = value;}
  8.     }
  9.  
  10.     [ConfigurationProperty("eventLogInfo")]
  11.     public EventLogInfoElement LogInfo
  12.     {
  13.         get{return (EventLogInfoElement)this["eventLogInfo"];}
  14.         set{this["eventLogInfo"] = value;}
  15.     }
  16.  
  17.     [ConfigurationProperty("sites")]
  18.     [ConfigurationCollection(typeof(UrlElementCollection),
  19.         AddItemName="add", ClearItemsName="clear",
  20.         RemoveItemName="remove")]
  21.     public UrlElementCollection Sites
  22.     {
  23.         get{return (UrlElementCollection)this["sites"];}
  24.         set{this["sites"] = value;}
  25.     }
  26. }

Note the use of two attributes for the ConfigurationElementCollection – we still use the ConfigurationProperty attribute to give the name of the collection in the configuration file, but we also use the ConfigurationCollection attribute to give add, clear and remove keywords that can be used in the config file. We’re also required to provide the type of the collection using this attribute.

One more change is required before we can use WscConfigurationSection, we need to let the runtime know the section to load in the configuration file and which type to load it with. We do this in the configuration file itself, within a <configSections> section. Within <configSections>, we’ll put a <sectionGroup> in to refer to the section group named <alex>, and within that section group we’ll put a <section> to represent the <wsc> section:

  1. <configSections>
  2.     <sectionGroup name="alex">
  3.         <section name="wsc"
  4.             type="Web_Site_Checker.WscConfigurationSection,
  5.             Web Site Checker"/>
  6.     </sectionGroup>
  7. </configSections>

For the type attribute of section, the class name including namespace is Web_Site_Checker.WscConfigurationSection, and the name of the assembly that holds the type is ‘Web Site Checker’, not ‘Web_Site_Checker’. I named my project ‘Web Site Checker’ and namespaces can’t have white space, so underscores are used instead.

There, we’ve got our classes, we just need to access the configuration file information using them, and this is how we do it:

  1. WscConfigurationSection section = (WscConfiguration)
  2.     ConfigurationManager.GetSection("alex/wsc");
  3.  
  4. /*Create a new web site checker using information about
  5. the polling interval and event logging from App.config:*/
  6. WebsiteChecker wsc =
  7.     new WebSiteChecker(section.PollingInterval,
  8.     section.LogInfo.LogName, section.LogInfo.EventSource);
  9.  
  10. //Get a list of the site urls to check:
  11. List<string> urls = new List<string>(section.Sites.Count);
  12.  
  13. foreach(UrlElement ue in section.Sites)
  14. {
  15.     urls.Add(eu.Url);
  16. }
  17.  
  18. //Start checking the urls that we got from the wsc config section:
  19. wsc.StartChecking(urls);

 

There, hopefully that’ll be of some use, especially setting up collections in the configuration file. Using the new configuration classes in .NET 2.0 can be hard work initially, but once you’ve got your head round them, you might find that you quite like them.

Share and Enjoy:
  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • email
  • LinkedIn
  • Technorati

2 thoughts on “Configuring a .NET 2.0 Application Using the ConfigurationSection class

  1. Pingback: The ConfigurationValidatorBase class | alexhumphrey.me.uk

  2. Pingback: The ConfigurationValidatorBase class » Alex Humphrey's Programming Blog

Leave a Reply

Your email address will not be published. Required fields are marked *