Custom ConfigurationSections in .NET 2.0 .config Files

Recently, I was needing to store information about 5 instances of an application server that I was accessing from my program.  As I was entering the third set of values in <appSettings> section I decided to go a better route.  What I wanted seemed simple: a section that worked exactly like the <connectionStrings> section, but with my own attributes.  After several hours with the documentation and some on-line research, I got what I wanted.  I was hoping it would only take 20-30 minutes.  In order to provide you with the experience I hoped to have, I have written this post.

First, let show you what I wanted my section to look like:

<acmeConfiguration>
 <add name="ERCOT"
  connectionName="AcmeER" fileDir="\\server\path" baseUrl="http://server:9999" />
  <add name="PM"
   connectionName="AcmePM" fileDir="\\server2\path" baseUrl="http://serverxx:9901" />
</acmeConfiguration>

You will need to subclass three classes from System.Configuration namespace: ConfigurationSection, ConfigurationElementCollection, and ConfigurationElement which correspond to the <acmeConfiguration>, the set of elements within <acmeConfiguration>, and the <add> elements respectively.  Understanding the above is the key to simplifying this exercise.  Here’s the code that implements the section above:

public class AcmeConfigSection : ConfigurationSection {
[ConfigurationProperty("", IsRequired=true, IsDefaultCollection=true)]
  public AcmeInstanceCollection Instances {
   get { return (AcmeInstanceCollection) this[""]; }
   set { this[""] = value; }
  }
}

public class AcmeInstanceCollection : ConfigurationElementCollection {
  protected override ConfigurationElement CreateNewElement() {
   return new AcmeInstanceElement();
  }
  protected override object GetElementKey(ConfigurationElement element) {
   return ((AcmeInstanceElement) element).Name;
  }
}
public class AcmeInstanceElement : ConfigurationElement {
  [ConfigurationProperty("name", IsKey=true, IsRequired=true)]
  public string Name {
   get { return (string) base["name"]; }
   set { base["name"] = value; }
}

  [ConfigurationProperty("connectionName", IsRequired=true)]
  public string ConnectionName {
   get { return (string)base["connectionName"]; }
   set { base["connectionName"] = value; }
  }

  [ConfigurationProperty("fileDir", IsRequired = true)]
  public string FileDir {
   get { return (string)base["fileDir"]; }
   set { base["fileDir"] = value; }
  }

  [ConfigurationProperty("baseUrl", IsRequired = true)]
  public string BaseUrl {
   get { return (string)base["baseUrl"]; }
   set { base["baseUrl"] = value; }
  }
 }

Finally, for convenience, I created a class to provide static access to this collection similar to System.Configuration.ConfigurationManager.ConnectionStrings:

public class AcmeConfig {
  protected static Dictionary<string, AcmeInstanceElement> _instances;
  static AcmeConfig() {
   _instances = new Dictionary<string,AcmeInstanceElement>();
   AcmeConfigSection sec = (AcmeConfigSection) System.Configuration.ConfigurationManager.GetSection("AcmeConfiguration");
   foreach ( AcmeInstanceElement i in sec.Instances ) {
    _instances.Add(i.Name, i);
   }
  }
  public static AcmeInstanceElement Instances(string instanceName) {
   return _instances[instanceName];
  }

  private AcmeConfig() {
  }

}

That’s it.  I wish MS would put a sample like mine in the docs because I think this is what 99% of developers are looking for.

One Response to “Custom ConfigurationSections in .NET 2.0 .config Files”

  1. Sebastian Patten Says:

    Thanks for the useful information.

    The logic they used for implementing this kind simple custom XML configuration seems a bit too complex don’t you think?

    Also whats the deal with
    this[""]

    I also didn’t notice that i needed to make the collection items “Add” items. I at first tried to implement my own name for these nodes.

    Thanks again for the good resource – it saved me some time!


Leave a Reply