Saturday, October 20, 2012

C# Writing Custom Configuration Settings Section

Almost every C# application has its own Configuration Settings file also known as App.Config. If you look on your App.Config file you probably will see a list of key value pairs:
<add key="key0" value="value0" />
<add key="key1" value="value1" /> 
<add key="key2" value="value2" />
... 
But what if you need some more complex configurations? Something like this:
<MySection>
    <MySettings MyKey="John" MyValue1="Developer" MyValue2="Expert"/>
    <MySettings MyKey="Tomas" MyValue1="Developer" MyValue2="Junior"/>    
    <MySettings MyKey="Robert" MyValue1="Developer" MyValue2="Senior"/>
    <MySettings MyKey="Kurt" MyValue1="IT" MyValue2="Expert"/>
    <MySettings MyKey="Anna" MyValue1="HR" MyValue2="Senior"/>    
</MySection>
Today I'll show how to build this kind of Custom Configuration Settings in C#.

First of all, we have to define our class that will represent the whole configuration section. This class must be inherited from ConfigurationSection class. By the way, don't forget to include System.Configuration namespace. Also we need an Element class. This class will represent a single row in the section and it must be inherited from ConfigurationElement class. Third and the last class will represent the collection of our elements. Let's call it ElementCollection. This class must be inherited from ConfigurationElementCollection. Let's see the source code:

Element.cs:
public class Element : ConfigurationElement
{
    private const string ATTRIBUTE_MYKEY = "MyKey";
    private const string ATTRIBUTE_MYVALUE1 = "MyValue1";
    private const string ATTRIBUTE_MYVALUE2 = "MyValue2";
    
    [ConfigurationProperty(ATTRIBUTE_MYKEY, IsRequired = true, IsKey = true)]        
    public string MyKey
    {
        get { return (string)this[ATTRIBUTE_MYKEY]; }
        set { this[ATTRIBUTE_MYKEY] = value; }
    }

    [ConfigurationProperty(ATTRIBUTE_MYVALUE1, IsRequired = true, IsKey = false)]        
    public string MyValue1
    {
        get { return (string)this[ATTRIBUTE_MYVALUE1]; }
        set { this[ATTRIBUTE_MYVALUE1] = value; }
    }

    [ConfigurationProperty(ATTRIBUTE_MYVALUE2, IsRequired = true, IsKey = false)]        
    public string MyValue2
    {
        get { return (string)this[ATTRIBUTE_MYVALUE2]; }
        set { this[ATTRIBUTE_MYVALUE2] = value; }
    }    
}
Notice that above each property there is ConfigurationProperty attribute. Also MyKey property has IsKey attribute set to true. Let's see now ElementCollection class which represents the collection of elements:

ElementCollection.cs:
public class ElementCollection : ConfigurationElementCollection
{
    public ElementCollection()
    {
        this.AddElementName = "MySettings";
    }

    protected override object GetElementKey(ConfigurationElement element)
    {
        return (element as Element).MyKey;
    }

    protected override ConfigurationElement CreateNewElement()
    {
        return new Element();
    }

    public new Element this[string key]
    {
        get { return base.BaseGet(key) as Element; }
    }

    public Element this[int ind]
    {
        get { return base.BaseGet(ind) as Element; }
    }
}
I override GetElementKey method in order to determine the key attribute in the element. In our case MyKey attribute is our key in configuration element. And finally here is the code of Section class:

Section.cs:
public class Section : ConfigurationSection
{
    public const string sectionName = "MySection";

    [ConfigurationProperty("", IsDefaultCollection = true)]
    public ElementCollection MySettings
    {
        get
        {
            return this[""] as ElementCollection;
        }
    }

    public static Section GetSection()
    {
        return (Section)ConfigurationManager.GetSection(sectionName);
    }
}
We almost done. Before we can use our configuration section we must specify the name of our custom configuration section, configuration section class namespace and the assembly name where the configuration section classes are located:

<configuration>

  <configSections>
    <section name="MySection" type="CustomConfigurationSection.CustomConfig.Section, CustomConfigurationSection" />
  </configSections>
  
  <MySection>
    <MySettings MyKey="John" MyValue1="Developer" MyValue2="Expert"/>
    <MySettings MyKey="Tomas" MyValue1="Developer" MyValue2="Junior"/>
    <MySettings MyKey="Robert" MyValue1="Developer" MyValue2="Senior"/>
    <MySettings MyKey="Kurt" MyValue1="IT" MyValue2="Expert"/>
    <MySettings MyKey="Anna" MyValue1="HR" MyValue2="Senior"/>
  </MySection>

</configuration>
Here is how we access our configurations:
Console.Write(section.MySettings["John"].MyValue1);
Console.Write(section.MySettings["Anna"].MyValue2);
Download the source code (Visual Studio 2010 project).

7 comments:

  1. Configuration system failed to initialize :(

    ReplyDelete
  2. Thanks this was just what I was looking for :) helped me a lot!!

    Paul

    ReplyDelete
  3. I have been looking for a complete example like yours. Thank you for your post. It really helped me a lot !!!. Keep posting articles like these.

    ReplyDelete
  4. Hello,

    Thank you for the example. It is very clear and concise, up until you are outputting your XML values.

    Console.Write(section.MySettings["John"].MyValue1);
    Console.Write(section.MySettings["Anna"].MyValue2);

    The path that you are using to call your values from your app.config file is not working for me. I am seeing an issue with section (lowercase) as not being a recognized class.

    Can you please provide a little more guidance regarding the output approach that you are utilizing?

    Thank you in advance.

    Matt

    ReplyDelete
  5. Many thanks for your explanation. Very useful to me!

    ReplyDelete
  6. Hi!

    It's not completely clear for me how can we add a new item to the config file using C#?
    Can you provide an example, please?

    ReplyDelete
    Replies
    1. Hi,
      Just download the source code from here: http://www.mediafire.com/?57eo3dxadw0rac3

      Delete