Custom Configuration Section in C#

A very familiar way of implementing the frequently changing value in an application is by storing them in a configuration file’s <appSettings> section. When the project is big, storing too many values in application settings is not a suggested approach, as this can lead to confusions and many other integration problems. Many at times we have seen when the code is moved from a development environment to a production environment there is a mismatch in the the configuration or we loose out on some important values. These issues can be eliminated by simply using a custom configuration section. A project constitutes of many modules and each module will have configuration values specific to them. So it will be a good idea to group them to a single section, and every  module’s configuration values will reside in their respective section. This way by just looking at the configuration one can figure out which value relates to what module. It is also suggested to have a common section so that these values can be accessed by all the modules and will reduce duplication of values.

Going forward you will learn about creating custom configuration section, the corresponding value holder class, and properties to access them through out the application. I will make the demo simple to a console application, so that it is easy to understand.

Start a new Console application and add an application configuration file to it. Also reference System.Configuration.dll.

What’s in the Configuration?

  1. <?xml version=1.0 encoding=utf-8 ?>
  2. <configuration>
  3.     <configSections>
  4.         <section name=MyConfiguration type=ConfigurationC.MyConfiguration, ConfigurationC/>
  5.     </configSections>
  6.     <!– Configuration settings for MyConfiguration Starts –>
  7.     <MyConfiguration
  8.             To=support@nnish.com
  9.             From=sales@nnish.com>
  10.         <Messages>
  11.             <Message Name=Email Value=email/>
  12.             <Message Name=Sms Value=sms/>
  13.             <Message Name=Tweet Value=tweet />
  14.         </Messages>
  15.     </MyConfiguration>
  16.     <!– Configuration settings for MyConfiguration Ends –>
  17. </configuration>

Lets break this into bits and pieces. Notice the <configSections> element –this is where you register your custom configuration. To add a custom configuration – add an element <section name=”” type=””/>.

  • name – represents the name of the custom configuration
  • type – used as <namespace.Type>, <AssemblyName> (Type is the corresponding class which inherits ConfigurationSection)

And the <MyConfiguration>element is nothing but the custom configuration section which contains custom values stored.  I will explain multiple ways of storing in the config files and accessing them from the application. In the config, I store some values as the attribute of the main element, the main element has the sub element <Messages> and that in turn has the collection of <Messages> having attributes “Name” and “Value”. This can be easily related to <add> element in the <appSettings>.

What’s in the Code?

Now let us go ahead and build the classes for accessing these values in the application.

Remember these:

  • There should be a class in the application representing each element (including the sub elements) in the configuration file.
  • Class holding the custom Configuration Section should inherit from CustomSection
    • public class MyConfiguration : ConfigurationSection
  • The attributes/elements can be represented as a property which is of type ConfigurationProperty in the parent class.
  • Class representing an element collection should inherit from ConfigurationElementCollection
    • public class MessageCollection : ConfigurationElementCollection
  • Class representing an element should inherit from ConfigurationElement
    • public class MessageElement : ConfigurationElement

Since <Message> is the last child element, write the corresponding class for it first, and then <Messages> which is its parent and it holds the collection of <Messages> and finally the class for <MyConfiguration> which has attributes represented as properties in itself.

Element: <Message> – Class: MessageElement

  1. using System.Configuration;
  2. namespace ConfigurationC
  3. {
  4.     /// <summary>
  5.     /// Class holds the <Message> element
  6.     /// </summary>
  7.     public class MessageElement : ConfigurationElement
  8.     {
  9.         // Holds the Name attribute of the Message
  10.         private static readonly ConfigurationProperty messageName =
  11.             new ConfigurationProperty(“Name”, typeof(string), string.Empty, ConfigurationPropertyOptions.IsRequired);
  12.         // Holds the Value attribute value of Message.
  13.         private static readonly ConfigurationProperty messageValue =
  14.             new ConfigurationProperty(“Value”, typeof(string), string.Empty, ConfigurationPropertyOptions.IsRequired);
  15.         public MessageElement()
  16.         {
  17.             base.Properties.Add(messageName);
  18.             base.Properties.Add(messageValue);
  19.         }
  20.         /// <summary>
  21.         /// Name
  22.         /// </summary>
  23.         [ConfigurationProperty(“Name”, IsRequired = true)]
  24.         public string Name
  25.         {
  26.             get { return (string)this[messageName]; }
  27.         }
  28.         /// <summary>
  29.         /// Value
  30.         /// </summary>
  31.         [ConfigurationProperty(“Value”, IsRequired = true)]
  32.         public string Value
  33.         {
  34.             get { return (string)this[messageValue]; }
  35.         }
  36.     }
  37. }

Explanation:

  • <Message> element has attributes “name” and “value” which are represented as ConfigurationProperty and its initialization takes the following parameters
    • name: The name of the configuration entity.  
    • type: The type of the configuration entity.
    • defaultValue: The default value of the configuration entity.
    • options:  One of the System.Configuration.ConfigurationPropertyOptions enumeration values
  • In the constructor add these properties to the base class Property Collection
  • Expose them as public property

Element: <Messages> – Class: MessageCollection

  1. using System.Configuration;
  2. namespace ConfigurationC
  3. {
  4.     [ConfigurationCollection(typeof(MessageElement), AddItemName = “Message”,
  5.          CollectionType = ConfigurationElementCollectionType.BasicMap)]
  6.     public class MessageCollection : ConfigurationElementCollection
  7.     {
  8.         protected override ConfigurationElement CreateNewElement()
  9.         {
  10.             return new MessageElement();
  11.         }
  12.         protected override object GetElementKey(ConfigurationElement element)
  13.         {
  14.             return ((MessageElement)element).Name;
  15.         }
  16.      
  17.         new public MessageElement this[string name]
  18.         {
  19.             get { return (MessageElement)BaseGet(name); }
  20.         }
  21.     }
  22. }

Explanation:

  • MessageCollection class is inherited from the abstract class ConfigurationElementCollection and two of its abstract methods CreateElement() and GetElementKey() needs to be overridden
  • CreateElement() creates the new instance of the MessageElement
  • GetElementKey() Gets the element key for a Message element (we define Name attribute as the key, so that the value can be retrieved using the name)
  • new public MessageElement this[string name] – add this to retrieve the value with the key name. For e.g: ConfigurationManager.AppSettings[“test”];

 

Element: <MyConfiguration> – Class: MyConfiguration (Putting them all together[ConfigurationSection ])

  1. using System.Configuration;
  2. namespace ConfigurationC
  3. {
  4.     public class MyConfiguration : ConfigurationSection
  5.     {
  6.         private static readonly ConfigurationProperty toAttribute =
  7.              new ConfigurationProperty(“To”, typeof(string), string.Empty, ConfigurationPropertyOptions.IsRequired);
  8.         
  9.         private static readonly ConfigurationProperty fromAttribute =
  10.              new ConfigurationProperty(“From”, typeof(string), string.Empty, ConfigurationPropertyOptions.IsRequired);
  11.         private static readonly ConfigurationProperty messagesElement =
  12.              new ConfigurationProperty(“Messages”, typeof(MessageCollection), null, ConfigurationPropertyOptions.IsRequired);
  13.         public MyConfiguration()
  14.         {
  15.             base.Properties.Add(toAttribute);
  16.             base.Properties.Add(fromAttribute);
  17.             base.Properties.Add(messagesElement);
  18.         }
  19.         /// <summary>
  20.         /// To
  21.         /// </summary>
  22.         [ConfigurationProperty(“To”, IsRequired = true)]
  23.         public string To
  24.         {
  25.             get { return (string)this[toAttribute]; }
  26.         }
  27.         
  28.         /// <summary>
  29.         /// From
  30.         /// </summary>
  31.         [ConfigurationProperty(“From”, IsRequired = true)]
  32.         public string From
  33.         {
  34.             get { return (string)this[fromAttribute]; }
  35.         }
  36.         /// <summary>
  37.         /// Messages Collection
  38.         /// </summary>
  39.         [ConfigurationProperty(“Messages”, IsRequired = true)]
  40.         public MessageCollection Messages
  41.         {
  42.             get { return (MessageCollection)this[messagesElement]; }
  43.         }
  44.     }
  45. }

Explanation:

  • Add all the Attributes and Elements as the ConfigurationProperty of corresponding type.

And the Program.cs

  1. using System;
  2. using System.Configuration;
  3. namespace ConfigurationC
  4. {
  5.    public class Program
  6.     {
  7.         public static MyConfiguration MyConfig;
  8.         static void Main(string[] args)
  9.         {
  10.             MyConfig = GetConfiguration();
  11.             Console.WriteLine(“This program comes with no warranty!”);
  12.             Console.WriteLine(“Values found in the configuration”);
  13.             Console.WriteLine(“To: “ + MyConfig.To);
  14.             Console.WriteLine(“From: “ + MyConfig.From);
  15.             Console.WriteLine(“Message Email: “ + MyConfig.Messages[“Email”].Value);
  16.             Console.WriteLine(“Message Sme: “ + MyConfig.Messages[“Sms”].Value);
  17.             Console.WriteLine(“Message Tweet: “ + MyConfig.Messages[“Tweet”].Value);
  18.             Console.ReadLine();
  19.         }
  20.         private static MyConfiguration GetConfiguration()
  21.         {
  22.             return (MyConfiguration)ConfigurationManager.GetSection(“MyConfiguration”);
  23.         }
  24.     }
  25. }

Above code snippet is self explanatory.

I hope I was able to walk you through a step by step process of a developing hello world Custom Configuration section.

Download the code!

Cheers!