h1

Custom web.config settings

October 11, 2007

Most application settings inside a Web.config file can be created inside the <appsettings> section – a collection of name/value pair settings can serve many purposes such as mailserver settings, email settings and on/off flags for certain application functions.

Sometimes more complicated setting requirements involve the need for more than simple name and value pairs and here I will illustrate how to create custom settings in the web.config file.

I’m going to use a simplified version of a recent real example to illustrate this – a syndication feed setting that was required in a recent application we built.
The requirements were for a number of custom settings to identify:

  • a distinctive url pattern that corresponds to a particular feed
    (e.g. /news/ )
  • what class to use to process this feed at run-time
    (utilising dynamic instantiation using reflection)
  • a name to describe the feed

In order to fulfill the requirement are going to do the following:

  1. Create a custom configuration section entry in the web.config file
  2. Input the section declaration itself and the actual settings
  3. Create a section handler class to parse the settings
  4. Create a class that will represent each individual setting
  5. Encapsulate the read of the config section

1. Creating the custom section

A custom section can be created inside the <configSections> node of the web.config file and we declare the name and type which represents the class that handles the section.
In our example, the web.config custom section looks like this:

<configSections>  

<section name="SyndicationFeeds" _
    type="Biscuit.SyndicationFeedsSectionHandler, Biscuit" />  

</configSections>

Here we are creating a section called SyndicationFeeds and we are instructing that the section handler to use is the SyndicationFeedsSectionHandler class in the Biscuit assembly.

2. The section declaration

The next step is the declaration of the section itself and because this is all about customisation, you can describe this section as you see fit.
In our example the actual section declaration looks like this:

<SyndicationFeeds>  

 <Feed Name="Test" Pattern="*/test/*" _
    Class="Biscuit.Feeds.TestFeed" Assembly="Biscuit"/>  

 <Feed Name="Article" Pattern="*/news/*" _
    Class="Biscuit.Feeds.NewsFeed" Assembly="Biscuit"/>  

 <Feed Name="Comment" Pattern="*/comments/*" _
    Class="Biscuit.Feeds.CommentFeed" Assembly="Biscuit"/>  

</SyndicationFeeds>

Here we are declaring three settings and each have the following attributes:

  • Name
  • Pattern
  • Class
  • Assembly

3. The section handler class

The class used to handle the custom config section needs to implement the IConfigurationSectionHandler interface which requires a Create method that is called when the section is read:

public object Create(object parent, object configContext, _
       System.Xml.XmlNode section)

Using the Xml object passed into the method, our custom code can parse each node of section and read the attributes and create objects based on them:

public object Create(object parent, object configContext, _
     System.Xml.XmlNode section)
{
    foreach(XmlNode feed in section.ChildNodes)
    {
       //do something
    }
    return xxxxx;
}

4. The setting class

We now want to create a class that can represent the values of the setting and we can do so with properties on the class for each attribute of the setting we declared in step 2:


public class SyndicationFeedSetting
{
   private string _name;
   public string Name
   {
      get { return _name; }
   }

   private string _pattern;
   public string Pattern
   {
      get { return _pattern;}
   }

   private string _class;
   public string Class
   {
      get { return _class; }
   }

   private string _assembly;
   public string Assembly
   {
      get { return _assembly; }
   }

   // Constructor
   public SyndicationFeedSetting(string name, _
   string pattern, string className, string assembly)
   {
      _name = name;
      _pattern = pattern;
      _class = className;
      _assembly = assembly;
   }
}

We can now fill in the blanks in our section handler so that as the nodes are parsed we create a list of these setting classes:

public object Create(object parent, object configContext, _
       System.Xml.XmlNode section)
{
   ArrayList feedList = new ArrayList();  

  foreach(XmlNode feed in section.ChildNodes)
    {
       feedList.Add(new SyndicationFeedSetting( _
              feed.Attributes["Name"].Value, _
              feed.Attributes["Pattern"].Value, _
              feed.Attributes["Class"].Value, _
              feed.Attributes["Assembly"].Value) );
    }  

    return feedList;
}

(Note: this is 1.1 code that we were using. I have not demonstrated here, but in 2.0 you could return a generic List<T> with type of SyndicationFeedSetting).

5. Encapsulate the read of the config section

It is my suggestion that you also encapsulate the reading of the section from the web.config file. This is especially relevant if you are using in multiple areas in your code as typing the following in multiple places is a bit messy:

System.Configuration.ConfigurationSettings.GetConfig(“SyndicationFeeds”);

Having this declaration in multiple areas complicates the process of future improvements or changes to the code.
By wrapping the retrieval inside another class you can have one point of change.


public class SyndicationConfigurationManager
{
    private SyndicationConfigurationManager()
   {
      //no construction allowed.
    }  

    public static ArrayList GetFeeds()
   {
      return (ArrayList)System.Configuration._
       ConfigurationSettings.GetConfig("SyndicationFeeds");
    }
}

Using the code and further Improvements

To use the above, in your code you now retrieve the settings (as an ArrayList currently, but see below for improvements) with a simple call to:


ArrayList feeds = SyndicationConfigurationManager.GetFeeds();

The above samples of code can be further improved in certain areas and has been written here to be purposefully compact.
For example, there is no error checking of the parameters in the handler class and more importantly the SyndicationFeedSetting class itself (on constructor parameters).

You can also change the SyndicationFeedManager class so that it returns an array of SyndicationFeedSettings as opposed to an ArrayList making it more type-safe at compile time.
As mentioned earlier, in 2.0 you can achieve this with a generic List being returned in both cases.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: