Web.config - Create your own custom section

Yoann BlossierYoann Blossier
6 min read

Here's a topic that's really interesting for many developers who like to organize their code a bit.

Having a custom configuration section in a configuration file is the best approach when that configuration involves a business need, a connection to a partner, a service, or something similar. But how exactly do you go about creating your own configuration section with its own properties?

As you'll see, it's actually pretty straightforward, and it's surprising we haven't done it before ๐Ÿ˜‰.


The simple section

The most simple configuration section is certainly the one you already use through the existing one AppSettings. Now lets see how to create a similar one.

  1. Create a new library project in Visual Studio here called MyLibrary

  2. Create a new class here called MyCustomSection

using System.Configuration;

namespace MyLibrary
{
    public class MyCustomSection : ConfigurationSection 
    { 
        public static MyCustomSection GetConfig()
        {
            return (MyCustomSection)ConfigurationManager.GetSection(SectionName) ?? new MyCustomSection();
        }

        /// <summary>
        /// The string name of the section in the configuration file as defined in its XML schema
        /// </summary>
        public const string SectionName = "mySection";

        [System.Configuration.ConfigurationProperty("", IsDefaultCollection = true, IsRequired = false)]
        [ConfigurationCollection(typeof(KeyValueConfigurationCollection), AddItemName = "add")]
        public KeyValueConfigurationCollection Settings { 
            get { 
                var o = this[""];
                return o as KeyValueConfigurationCollection;
            } 
        }
    }
}

This class lets us use a new configuration section after previously declared in the head of the web.config.

  1. Create a new ASP.Net WebForms project in Visual Studio

  2. Add your library in references

  3. Edit the web.config as below

<configuration>
    <configSections>
        <section name="mySection" type="MyLibrary.MyCustomSection, MyLibrary" requirePermission="false"/>
    </configSections>
    <mySection>
        <add key="param1" value="value1"/>
        <add key="param2" value="value2"/>
    </mySection>
</configuration>

The complex section

Now, since the definition of "complex" really depends on you and what you need, I'll cover a bit of everything here. Of course, it might not cover your specific case, but hey, everyone needs to put in some effort, right? ๐Ÿ˜Ž

I want to create a new section to handle the multiple parameter we can have to use to connect to an API provider as Google, Facebook, Twitter or our proper business partner.

Please find the class I wrote to illustrate. I will detail just after.

using System.Configuration;

namespace MyLibrary
{
    /// <summary>    
    /// The configuration section class determines the partners configuration elements
    /// </summary>
    public class PartnerConfigSection : ConfigurationSection
    {
        public static PartnerConfigSection GetConfig()
        {
            return (PartnerConfigSection)ConfigurationManager.GetSection(SectionName) ?? new PartnerConfigSection();
        }

        /// <summary>
        /// The string name of the section in the configuration file as defined in its XML schema
        /// </summary>
        public const string SectionName = "partnerConfig";

        /// <summary>
        /// The XML namespace. Used to solve live compilation issue
        /// </summary>
        [ConfigurationProperty("xmlns", IsRequired = false)]
        public string XmlNamespace
        {
            get { return (string)this["xmlns"]; }
            set { this["xmlns"] = value; }
        }

        /// <summary>
        /// The name of partners group
        /// </summary>
        [ConfigurationProperty("name", IsRequired = false)]
        public string Name
        {
            get { return (string)this["name"]; }
            set { this["name"] = value; }
        }

        /// <summary>
        /// The partner configuration to use it(s) service(s)
        /// </summary>
        [ConfigurationProperty("", IsDefaultCollection = true, IsRequired = false)]
        [ConfigurationCollection(typeof(PartnerConfigurationElement), AddItemName = "partner")]
        public PartnerConfigurationCollection Partners
        {
            get { return (PartnerConfigurationCollection)this[""]; }
        }
    }
}

In this class, you'll notice it has a Name property and Partners property as a collection.

There's also something interesting about the XmlNamespace propertyโ€”it's only there to enable live compilation of the web.config when you use it. If you want proof rather than taking my word for it (which you should always do ๐Ÿ˜Š), try removing it and see what happens ๐Ÿ˜‰.


Now, please found the PartnerConfigurationCollection class that I used for Partners property

using System.Configuration;

namespace MyLibrary
{
    /// <summary>
    /// The configuration element collection contains all definitions
    /// </summary>
    public class PartnerConfigurationCollection : ConfigurationElementCollection
    {
        /// <summary>
        /// Manage the element described by the <paramref name="name"/>
        /// </summary>
        /// <param name="name">The key value of the element to retrieve in the collection</param>
        /// <returns>The configuration element found in the collection</returns>
        public new PartnerConfigurationElement this[string name]
        {
            get { return (PartnerConfigurationElement)this.BaseGet((object)name); }
            set { int index = -1; PartnerConfigurationElement configurationElement = (PartnerConfigurationElement)this.BaseGet((object)name); if (configurationElement != null) { index = this.BaseIndexOf(configurationElement); this.BaseRemoveAt(index); } this.BaseAdd(index, value); }
        }
        /// <summary>
        /// Create a new element in the collection
        /// </summary>
        /// <returns>The newly created element</returns>
        protected override ConfigurationElement CreateNewElement() { return new PartnerConfigurationElement(); }

        /// <summary>
        /// Get the key of the configuration element
        /// </summary>
        /// <param name="element">The configuration element</param>
        /// <returns>The configuration element key</returns>
        protected override object GetElementKey(ConfigurationElement element) { return ((PartnerConfigurationElement)element).Name; }
    }
}

And now, the class of the collection element use above.

using System.Configuration;

namespace MyLibrary
{
    /// <summary>
    /// The configuration element contains the configuration values of partner
    /// </summary>
    public class PartnerConfigurationElement : ConfigurationElement
    {
        /// <summary>
        /// Get or set the name of partner use as unique key
        /// </summary>
        [ConfigurationProperty("Name", IsRequired = true)]
        public string Name
        {
            get { return (string)this["Name"]; }
            set { this["Name"] = value; }
        }

        /// <summary>
        /// Get or set the status of availability of the identity provider
        /// </summary>
        [ConfigurationProperty("Enabled", DefaultValue = "false", IsRequired = false)]
        public bool Enabled
        {
            get { return (bool)this["Enabled"]; }
            set { this["Enabled"] = value; }
        }

        /// <summary>
        /// Get or set the identifier of customer for the partner usage
        /// </summary>
        [ConfigurationProperty("ClientId", IsRequired = false)]
        public string ClientId
        {
            get { return (string)this["ClientId"]; }
            set { this["ClientId"] = value; }
        }

        /// <summary>
        /// Get or set the secret key of customer for the partner usage
        /// </summary>
        [ConfigurationProperty("ClientSecret", IsRequired = false)]
        public string ClientSecret
        {
            get { return (string)this["ClientSecret"]; }
            set { this["ClientSecret"] = value; }
        }

        /// <summary>
        /// Get or set the parameters collection
        /// </summary>
        [ConfigurationProperty("", IsDefaultCollection = true, IsRequired = false)]
        [ConfigurationCollection(typeof(KeyValueConfigurationCollection), AddItemName = "add")]
        public KeyValueConfigurationCollection Parameters
        {
            get { return (KeyValueConfigurationCollection)this[""]; }
            set { this[""] = value; }
        }
    }
}

Now we have the entire definition of the custom configuration section and we can declare in the web.config to use it afterwards.

  1. Create a new ASP.Net WebForms project in Visual Studio

  2. Add your library in references

  3. Edit the web.config as below

<configuration>   
    <configSections>     
        <section name="partnerConfig" type="MyLibrary.PartnerConfigSection, MyLibrary" requirePermission="false"/>
    </configSections>
    <partnerConfig>
        <Partners>
            <partner Name="Partner1" Enabled="true">
                <add key="param1" value="2"/>
                <add key="url" value="https://api.test.com/"/>
            </partner>
            <partner Name="Partner2" ClientId="12345" ClientSecret="azerty" Enabled="true">
                <add key="url" value="https://api.test.com/"/>
            </partner>
        </Partners>
    </partnerConfig>
</configuration>

We have seen the complex view of custom configuration section where we have mixed properties and collection elements in the same definition.

Now, you know how to do it, go for it.

Resources

Please find the project illustrating this article on my Github, here.


Let's Connect!

Hi, I'm Yoann. I work as a full-stack developer, solution architect.

If you enjoyed this article, you might enjoy my other content, too.

Github:yblossier

LinkedIn:/in/yoannblossier

Buy Me A Coffee:A special thank you for your support๐Ÿต

Thank you for joining me today.

Yoann

0
Subscribe to my newsletter

Read articles from Yoann Blossier directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Yoann Blossier
Yoann Blossier