Most .NET developers will need to store some application configuration information at some point. Most times developers choose to use the appSettings section in the configuration file for this purpose. Here’s an example of an appSettings configuration section:

<appsettings>
    <!--Misc Settings-->
    <add key="StandardHandlingFee" value="4.95" />
    <add key="PageSize" value="5" />
     ...
</appsettings>

Over time the number of configuration items tends to grow and managing them can become confusing. What you end up with is a seemingly endless list of key value pairs that are difficult to manage. Additionally the code required the access there values can start to get tedious.

using System;
using System.Configuration;

namespace Before
{
    class Program
    {
        static void Main(string[] args)
        {
            // Load Misc Settings
            decimal standardHandlingFee = Convert.ToDecimal(ConfigurationManager.AppSettings["StandardHandlingFee"]);
            int pageSize = Convert.ToInt32(ConfigurationManager.AppSettings["PageSize"]);

<pre><code>        // ... do work ...
    }
}
</code></pre>

}

.NET has the given developers the ability simplify this process by creating custom configuration sections. These custom configuration sections can help turn unstructured, untyped data into strongly-typed, straightforward elements. Basically, taking the almost meaningless key-value pairs and turning them into something more meaningful.

There are 3 pieces that makeup the custom configuration; a class that inherits from System.Configuration.ConfigurationSection; “registering” your configuration class in the configSections of your configuration file; and the XML configuration itself.

First is the class that handles how we access the configuration data.

using System;
using System.Configuration;

namespace After.Configuration
{
    public class TestAppConfigProviderSection : ConfigurationSection
    {
        public static readonly TestAppConfigProviderSection Current = (TestAppConfigProviderSection)ConfigurationManager.GetSection(&amp;quot;testAppConfigProvider&amp;quot;);

<pre><code>    [ConfigurationProperty(&amp;amp;quot;StandardHandlingFee&amp;amp;quot;, DefaultValue = &amp;amp;quot;4.95&amp;amp;quot;)]
    public decimal StandardHandlingFee
    {
        get { return (decimal)base[&amp;amp;quot;StandardHandlingFee&amp;amp;quot;]; }
        set { base[&amp;amp;quot;StandardHandlingFee&amp;amp;quot;] = value; }
    }

    [ConfigurationProperty(&amp;amp;quot;PageSize&amp;amp;quot;, DefaultValue = &amp;amp;quot;10&amp;amp;quot;)]
    public int PageSize
    {
        get { return (int)base[&amp;amp;quot;PageSize&amp;amp;quot;]; }
        set { base[&amp;amp;quot;PageSize&amp;amp;quot;] = value; }
    }
}
</code></pre>

}

This class is pretty straightforward, but there are some key things to take note of. First, the main ConfigurationSection class must derive from the System.Configuration.ConfigurationSection class.

Also, within the TestAppConfigProviderSection class I use a singleton style approach with the Current member. This helps make accessing the properties within the configuration section easy.

The configuration properties that the class is exposing should use the ConfigurationProperty attribute. The name that gets passed in this attribute should match the attribute name in the configuration file.

“Registering” our configuration section is done by adding a section the the configSections of the application’s .config file. The XML configuration is restructured to match how it is defined in our class. Here’s the new .config file after being refactored.

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
&lt;configuration&gt;
  &lt;configSections&gt;
    &lt;section name=&quot;testAppConfigProvider&quot; type=&quot;After.Configuration.TestAppConfigProviderSection, After&quot;/&gt;
  &lt;/configSections&gt;
  &lt;testAppConfigProvider StandardHandlingFee=&quot;4.95&quot; PageSize=&quot;10&quot; /&gt;
&lt;/configuration&gt;

Here’s our example code again, but using the custom configuration sections.

using System;
using After.Configuration;

namespace After
{
    class Program
    {
        static void Main(string[] args)
        {
            // Load Misc Settings
            decimal standardHandlingFee = TestAppConfigProviderSection.Current.StandardHandlingFee;
            int pageSize = TestAppConfigProviderSection.Current.PageSize;

<pre><code>        // ... do work ...
    }
}
</code></pre>

}

It is also possible to load the custom configuration sections from an external file like so:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
&lt;configuration&gt;
  &lt;configSections&gt;
    &lt;section name=&quot;testAppConfigProvider&quot; type=&quot;After.Configuration.TestAppConfigProviderSection, After&quot;/&gt;
  &lt;/configSections&gt;
  &lt;testAppConfigProvider configSource=&quot;testApp.config&quot; /&gt;
&lt;/configuration&gt;

Where testApp.config looks like this:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
&lt;testAppConfigProvider StandardHandlingFee=&quot;4.95&quot; PageSize=&quot;10&quot; /&gt;

One important note on using this method, you must make sure that you change the Copy to Output Directory property on the new .config file to either ‘Copy if newer’ or ‘Copy always’. Otherwise the file won’t get copied to the projects bin directory and the ConfigurationManager won’t be able to load the file.

This image has an empty alt attribute; its file name is copyifnewer_thumb_2.jpg

The benefits of using a custom configuration section handler are significant. Using the handler code is pretty straightforward and gives you less clutter in the appSettings as well as strong typing of your configuration elements.

Leave a Reply

I’m Peter

I’ve spent my career building software and leading engineering teams. I started as a developer and architect, grew into engineering leadership, and today I serve as a Chief Technology Officer.

Here, I share practical insights on technology, leadership, and building high-performing teams.

Connect with me on LinkedIn.

Discover more from Peter Mourfield

Subscribe now to keep reading and get access to the full archive.

Continue reading