Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / programming / architecture

ConfigurationParser for .NET

4.76/5 (6 votes)
28 Mar 2017LGPL33 min read 10.1K  
This article describes one of the easiest ways to read configurations from the App.config.

Introduction

In this article I would like to focus on problems people face with when they get settings from config files. Usually developers use comprehensive and complicated API from System.Configuration namespace and get settings step by step. In case when section we need to read has a simple structure (without nesting), then reading it doesn’t cause much troubles. However, when structure is more complex and/or has nested subsections, then parsing it might become a real headache. ConfigurationParser utility is specifically designed to overcome such problems and make read from config files a quick and simple process.

Installation

The library is available in NuGet. Alternatively you can get the source code from GitHub.

Usage

In order to demonstrate the power of the library, let’s imagine that our program requires settings for connecting to several external systems and databases as well as being able to send emails to system administrators. We decide that these settings should be placed into three sections.

XML
<ExternalSystemSettings>
    <Authenticationsettings>
        <login>DotNetCraft</login>
        <token>qwerty</token>
        <Urls>
            <url>https://github.com/DotNetCraft/ConfigurationParser</url>
            <url>https://github.com/DotNetCraft/ConfigurationParser</url>
        </Urls>      
    </Authenticationsettings>
    <Staffsettings token="{D0C148F7-83C0-41B0-8F18-B47CAB09AD99}" url="https://github.com/DotNetCraft/ConfigurationParser"/>
</ExternalSystemSettings>

<DatabasesSettings>
    <Mongosettings connectionstring="mongo.url" databasename="DotNetCraft"/>
    <Sqlsettings>
        <item key="TenantA">
            <value>
                <sqlsettings connectionstring="sql.TenantA.com">
            </sqlsettings></value>
        </item>
        <item>
            <key>TenantB</key>
            <value>
                <sqlsettings>
                    <connectionstring>sql.TenantB.com</connectionstring>
                </sqlsettings>
            </value>
        </item>     
    </Sqlsettings>
</DatabasesSettings>

<SmtpSettings host="gmail.com" sender="no-reply">
    <Recipients>clien1@gmail.com;clien2@gmail.com;clien3@gmail.com</Recipients>
</SmtpSettings>

Our next step is to create classes which will store the system settings.

C#
#region ExternalSystemSettings
class ExternalSystemSettings
{
    public AuthenticationServiceSettings AuthenticationSettings { get; set; }
    public StaffServiceSettings StaffSettings { get; set; }
}

class AuthenticationServiceSettings
{
    public string Login { get; set; }
    public string Token { get; set; }
    public List<string> Urls { get; set; }
}

class StaffServiceSettings
{
    public Guid Token { get; set; }
    public string Url { get; set; }
}
#endregion

#region DatabasesSettings
class DatabasesSettings
{
    public MongoDatabaseSettings MongoSettings { get; set; }
    public Dictionary<string, SqlSettings> SqlSettings { get; set; }
}

class MongoDatabaseSettings
{
    public string ConnectionString { get; set; }
    public string DatabaseName { get; set; }
}

class SqlSettings
{
    public string ConnectionString { get; set; }
}
#endregion

#region Smtp
class SmtpSettings
{
    public string Host { get; set; }
    public string Sender { get; set; }

    [CustomStrategy(typeof(SplitRecipientsCustomStrategy))]
    public List<string> Recipients { get; set; }
}
#endregion    

In config file we need to declare that we will be using ConfigurationParser.

XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>

<configSections>
    <section name="ExternalSystemSettings" type="DotNetCraft.ConfigurationParser.SimpleConfigurationSectionHandler, DotNetCraft.ConfigurationParser" />
    <section name="DatabasesSettings" type="DotNetCraft.ConfigurationParser.SimpleConfigurationSectionHandler, DotNetCraft.ConfigurationParser" />
    <section name="SmtpSettings" type="DotNetCraft.ConfigurationParser.SimpleConfigurationSectionHandler, DotNetCraft.ConfigurationParser" />
</configSections></configuration>    

Now we can easily read our configuration the following way:

C#
ExternalSystemSettings externalSystemSettings = (ExternalSystemSettings)(dynamic)ConfigurationManager.GetSection("ExternalSystemSettings");

or

C#
ExternalSystemSettings externalSystemSettings = (dynamic)ConfigurationManager.GetSection("ExternalSystemSettings");

After this code is executed we will have two object containing our settings. You might notice that we are not currently getting SmtpSettings. This is done in order to show additional abilities of the utility.

In different projects you might need to have various settings in configuration files and have your own logic how you process them. The utility is designed in a way that allows you to easily extend it by adding new strategies and in doing that cover all scenarios that you require. As an example, let’s have a look at Recipients section:

XML
<Recipients>clien1@gmail.com;clien2@gmail.com;clien3@gmail.com</Recipients>

This section contains a list of email addresses separated by semicolon. According to our requirements we and models we need to write each email as a separate element to an array. In order to achieve that we’re creating SplitRecipientsCustomStrategy class and implement ICustomMappingStrategy interface.

C#
class SplitRecipientsCustomStrategy : ICustomMappingStrategy
{
    #region Implementation of ICustomMappingStrategy

    public object Map(string input, Type itemType)
    {
        string[] items = input.Split(';');
        List<string> result = new List<string>();
        result.AddRange(items);
        //Some complex logic can be here if needed
        //For instance, check emails via RegEx.
        return result;
    }

    public object Map(XmlNode xmlNode, Type itemType)
    {
        string input = xmlNode.InnerText;
        return Map(input, itemType);
    }

    #endregion
}    

In this class we implement an algorithm we require to parse value from the section according to the task. Note that method Map(string input, Type itemType) is called if value was read from attribute while Map(XmlNode xmlNode, Type itemType) is called if value was read from section. In our case the value will be read from section.

After that we need to mark property Recipients with CustomStrategy attribute in which we write what strategy we would like to use for this field:

C#
[CustomStrategy(typeof(SplitRecipientsCustomStrategy))]
public List<string> Recipients { get; set; }

That’s it, now we’re able to read email setting.

C#
SmtpSettings smtpSettings = (dynamic)ConfigurationManager.GetSection("SmtpSettings");

As you can see, ConfigurationParser makes the process of reading config setting simple and smooth and saves you a lot of time. Moreover, the utility is easily extensible thanks to ability to introduce new strategies.

Conclusion

As you can see, ConfigurationParser makes the process of reading config setting simple and smooth and saves you a lot of time. Moreover, the utility is easily extensible thanks to ability to introduce new strategies.

I you have any questions or suggestions, please feel free to write them in comments and I will be glad to answer them.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)