Cinchoo – Application configuration made easy

1. Introduction

Download sample source files (Require .NET 4.0 / Visual Studio 2010)

Cinchoo – Application configuration is one of the feature Cinchoo framework provides for the developer.  Application configuration is the information that application reads/writes at run time from the source. .NET already provides extensive support through several predefined configuration section handlers for the developers. But require some pluming development work on top of them to complete the exercise.

Cinchoo framework simply them with less code and read/write configuration values to the underlying data sources seamlessly. Also it gives you the flexibility of interchanging the configuration sources through configuration without any code change. In the following sections, I’m going to provide you in detail on how to use them in your application.

Cinchoo configuration framework have the below powerful features

  • One single API to deal with configuration data with multiple sources
  • Two-way, type-safe configuration management
  • Create the configuration files, if those are missing
  • Generate the configuration sections, if not exists
  • During application run time, has the flexibility of changing the configuration sources without any restart or downtime needed.
  • Auto correct the section if it missing any entries in the configuration files.

2. Requirement

This configuration library is written in C# for the .NET 4.0 Framework. It is part of Cinchoo framework, which is a great library with lot of features like Configuration Management, common ApplicationHost, Shell features, etc.

3. “Hello World!” Sample

Let’s begin by looking into a simple example of an application consuming two configuration values name and message. name is required configuration value and msg is optional configuration value with default value 100, Madison Avenue, New York, NY 10010“. If msg is not configured, it will take the default value.

  • Download the latest Cinchoo binary here. (Nuget Command: Install-Package Cinchoo)
  • Open VS.NET 2010 or higher
  • Create a sample VS.NET (.NET Framework 4) Console Application project
  • Add reference to Cinchoo.Core.dll
  • Use the Cinchoo.Core and Cinchoo.Core.Configuration namespace
  • Copy and paste the below command line object
Namespace: Cinchoo.Core.Configuration

The heart of the Cinchoo configuration framework is in Cinchoo.Core.Configuration namespace. This namespace is available when you reference Cinchoo.Core.dll assembly in your project.

PS: Please turn on Reflection Permission in order to use this framework.

Listing 3.1 Defining Configuration Object

[ChoNameValueConfigurationSection("appSettings")]
public class AppSettings : ChoConfigurableObject
{
    [ChoPropertyInfo("name", DefaultValue = "Mark")]
    public string Name;

    [ChoPropertyInfo("address", DefaultValue = "100, Madison Avenue, New York, NY 10010")]
    public string Address;
}

By default, all public properties and fields will be treated as configuration properties. Each class member may be decorated using ChoPropertyInfoAttribute with the property name, default value, fallback value etc. Framework binds the members to the configuration attributes by the name.

The code above illustrates about defining configuration object. First thing define a configuration (ex. AppSettings) class from ChoConfigurableObject, it indicates that this object is a configuration object. And it must be decorated with one of the available configuration section attributes, will be discussed later. In this example, I’ve used ChoNameValueConfigurationSectionAttribute with appSettings as section name to complete the definition. It specifies that this configuration section is the NameValueConfigurationSection. With this definition, we turned the above configuration object provides name/value-pair configuration information from a configuration section.

Define configuration value members Name and Address either as public fields or properties with get and set in it. Decorate them with ChoPropertyInfo attribute to indicate that they are configuration members. In this sample, Name is the optional configuration member. It is given nameas configuration member name with the DefaultValue as Mark‘. It means that if the configuration value is missing from the source, it will be defaulted to DefaultValue.

Address configuration member is an optional member as well. It was given with addressas name with DefaultValue as 100, Madison Avenue, New York, NY 10010.

Once you have the configuration object defined as above, it is now ready to use in your application. Here is how you can create and use it.

Listing 3.2 Main Method

static void Main(string[] args)
{
    AppSettings appSettings = new AppSettings();
    Console.WriteLine(appSettings.ToString());

    //Update the name to 'Raj', see it is updating to source
    appSettings.Name = "Raj";

    ChoConsole.PauseLine();
}

We start by creating a new instance of AppSettings object, That’s all. All the heavy lifting of loading configuration values to the object is done by the framework under the hood.

Now compile this program and run. It will create the section in [appExeName].xml (HelloWorld.exe.xml) file under bin/Config folder.

Listing 3.3 HelloWorld.exe.xml

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="appSettings" type="Cinchoo.Core.Configuration.ChoNameValueSectionHandler, 
       Cinchoo.Core, Version=1.0.1.1, Culture=neutral, PublicKeyToken=b7dacd80ff3e33de" />
  </configSections>
  <appSettings>
    <add key="name" value="Raj" />
    <add key="address" value="100, Madison Avenue, New York, NY 10010" />
  </appSettings>
</configuration>

Writing code to provide custom configuration section to your application is very simple and straightforward. Vast bulk of dealing with configuration data is done by Cinchoo framework.

4. Types of Configuration Section Handlers

Cinchoo framework provides some configuration section handlers out of the box. Listed below are few of the available configuration section handlers:

  • ChoNameValueConfigurationSection – Provides name/value pair configuration information from a configuration section.
  • ChoDictionaryConfigurationSection – Provides key/value pair configuration information from a configuration section.
  • ChoSingleTagConfigurationSection – Handles configuration sections that are represented by a single XML tag in the configuration file.
  • ChoStandardAppSettingsConfigurationSection – Read/Write Key/Value pair from <appSettings> section
  • ChoIniConfigurationSection – Read/Write configuration values from INI files.
  • ChoRegistryConfigurationSection – Read/Write configuration values from System Registry.
  • ChoDbGenericKeyValueConfigurationSection – Read/Write configuration values from any databases.

4.1 ChoNameValueConfigurationSection

It provides access to name/value pair configuration information from configuration section. It uses NameValueCollection as the underlying storage, it means that values its stores are string->string pairs. It provides simple solutions, if you need a configuration to be efficient use ChoDictionaryConfigurationSection.

The below example illustrates how to define and use this section to consume the configuration values. Declare ChoNameValueConfigurationSectionAttribute to the configuration class to use this section handler.

Listing 4.1.1 Defining Configuration Object

[ChoNameValueConfigurationSection("appSettings")]
public class AppSettings : ChoConfigurableObject
{
    [ChoPropertyInfo("name")]
    public string Name;

    [ChoPropertyInfo("address", DefaultValue = "100, Madison Avenue, New York, NY 10010")]
    public string Address;
}

Once you instantiate an object, you are ready to consume the configuration values. The file below shows the layout of the configuration file produced when using this section handler.

Listing 4.1.2 HelloWorld.exe.xml

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="appSettings" type="Cinchoo.Core.Configuration.ChoNameValueSectionHandler, 
       Cinchoo.Core, Version=1.0.1.1, Culture=neutral, PublicKeyToken=b7dacd80ff3e33de" />
  </configSections>
  <appSettings>
    <add key="name" value="Raj" />
    <add key="address" value="100, Madison Avenue, New York, NY 10010" />
  </appSettings>
</configuration>

4.2 ChoDictionaryConfigurationSection

It provides access to key/value pair configuration information from configuration section. It is very similar to ChoNameValueConfigurationSection, but more efficient to consume configuration values.

The below example illustrates how to define and use this section to consume the configuration values. Declare ChoDictionaryConfigurationSectionAttribute to the configuration class to use this section handler.

Listing 4.2.1 Defining Configuration Object

[ChoDictionaryConfigurationSection("appSettings")]
public class AppSettings : ChoConfigurableObject
{
    [ChoPropertyInfo("name")]
    public string Name;

    [ChoPropertyInfo("address", DefaultValue = "100, Madison Avenue, New York, NY 10010")]
    public string Address;
}

Once you instantiate an object, you are ready to consume the configuration values. The file below shows the layout of the configuration file produced when using this section handler.

Listing 4.2.2 HelloWorld.xml

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="appSettings" type="Cinchoo.Core.Configuration.ChoDictionarySectionHandler, 
       Cinchoo.Core, Version=1.0.1.1, Culture=neutral, PublicKeyToken=b7dacd80ff3e33de" />
  </configSections>
  <appSettings>
    <add key="name" value="Raj" />
    <add key="address" value="100, Madison Avenue, New York, NY 10010" />
  </appSettings>
</configuration>

4.3 ChoSingleTagConfigurationSection

It handles configuration sections that are represented by a single XML tag in the configuration file. It is a very simple, elegant way to have values in the configuration file. Only downside is that it can contain only the simple values.

The below example illustrates how to define and use this section to consume the configuration values. Declare ChoSingleTagConfigurationSectionAttribute to the class to use this section handler.

Listing 4.3.1 Defining Configuration Object

[ChoSingleTagConfigurationSection("appSettings")]
public class AppSettings : ChoConfigurableObject
{
    [ChoPropertyInfo("name")]
    public string Name;

    [ChoPropertyInfo("address", DefaultValue = "100, Madison Avenue, New York, NY 10010")]
    public string Address;
}

Once you instantiate an object, you are ready to consume the configuration values. The file below shows the layout of the configuration file produced when using this section handler.

Listing 4.3.2 HelloWorld.xml

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="appSettings" 
    type="Cinchoo.Core.Configuration.ChoNameValueSectionHandler, Cinchoo.Core" />
  </configSections>
  <appSettings name="Raj" address="100, Madison Avenue, New York, NY 10010" />
</configuration>

4.4 ChoIniConfigurationSection

It handles the reading and writing of configuration values from INI file, a simple text files with basic structure composed of sections, properties and values. It is supported by some legacy platforms.

Listing 4.4.1 Sample INI file (AppSettings.ini)

; last modified 1 April 2001 by John Doe
[APP_SETTINGS]
NAME=John Doe
ADDRESS=Acme Widgets Inc.
 
[DATABASE]
; use IP address in case network name resolution is not working
SERVER=192.0.2.62     
PORT=143
FILE="payroll.dat"

This section simplifies the consumption of INI file values into configuration object by providing unified interface. The below example illustrates how to define and use this section to consume the INI values. Declare ChoIniConfigurationSectionAttribute to the configuration class to use this section handler.

Listing 4.4.2 Defining Configuration Object

[ChoIniConfigurationSection("appSettings", "APP_SETTINGS", "AppSettings.ini")]
public class AppSettings : ChoConfigurableObject
{
    [ChoPropertyInfo("name")]
    public string Name;

    [ChoPropertyInfo("address", DefaultValue = "100, Madison Avenue, New York, NY 10010")]
    public string Address;
}

The code above illustrates how the INI configuration section is specified to configuration object. It specifies the name of the INI file (AppSettings.ini) where the values will be consumed from/to. It can be addressed as absolute or relative file path. If the file name is specified without path, configuration manager will be looking for the file in the current executable folder. If the INI file not exists, it will be created automatically, containing all the configuration members with default values.

Besides that, you will have to specify the INI section (‘APP_SETTINGS’) name where all the configuration members values will be loaded from.

Once you instantiate an object, you are ready to consume the configuration values. The file below shows the layout of the configuration file produced when using this section handler.

Listing 4.4.3 HelloWorld.xml

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="appSettings" 
    type="Cinchoo.Core.Configuration.ChoNameValueSectionHandler, 
    Cinchoo.Core" />
  </configSections>
  <appSettings cinchoo:iniSectionName="APP_SETTINGS" 
  cinchoo:iniFilePath="AppSettings.ini" 
    xmlns:cinchoo="http://schemas.cinchoo.com/cinchoo/01/framework" />
</configuration>

4.5 ChoRegistryConfigurationSection

It handles the reading and writing of configuration values from system registry, a hierarchical database that stored configuration settings and options on Microsoft Windows operating systems.

Listing 4.5.1 Sample Registry image (HelloWorld)

This section simplifies the consumption of registry information into configuration object by providing unified interface. The below example illustrates how to define and use this section to consume the registry values. Declare ChoRegistryConfigurationSectionAttribute to the configuration class to use this section handler.

Listing 4.5.2 Defining Configuration Object

[ChoRegistryConfigurationSection("appSettings", @"HKCU\Software\HelloWorld")]
public class AppSettings : ChoConfigurableObject
{
    [ChoPropertyInfo("name")]
    public string Name;

    [ChoPropertyInfo("address", DefaultValue = "100, Madison Avenue, New York, NY 10010")]
    public string Address;
}

The code above illustrates how the registry configuration section is specified to configuration object. It specifies the location of the registry key where all the configuration values will be consumed from/to. Framework automatically creates the registry key and sub-keys automatically if not found.

Here are some of the shortcut names for well known registry roots can be used when you defining this section

  1. HKCU – HKEY_CURRENT_USER
  2. HKLM – HKEY_LOCAL_MACHINE
  3. HKCR – HKEY_CLASSESS_ROOT
  4. HKCC – HKEY_CURRENT_CONFIG

Once you instantiate an object, you are ready to consume the configuration values. The file below shows the layout of the configuration file produced when using this section handler.

Listing 4.5.3 HelloWorld.xml

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="appSettings" type="Cinchoo.Core.Configuration.ChoDictionarySectionHandler, 
    Cinchoo.Core" />
  </configSections>
  <appSettings cinchoo:registryKey="HKCU\Software\HelloWorld" 
    xmlns:cinchoo="http://schemas.cinchoo.com/cinchoo/01/framework" />
</configuration>

4.6 ChoSqlServerConfigurationSection

It handles the reading and writing of configuration values from Microsoft SqlServer database, a RDBMS from Microsoft designed for enterprise environment. A common widely used database in desktop environment.

This section handler allows multiple applications to store and consume centrally located configuration values.

First and foremost, you must create a configuration table in the targeted database as per the below schema.

Listing 4.6.1 Configuration table

CREATE TABLE APP_SETTINGS
(
    [KEY] VARCHAR (50) NOT NULL,
    VALUE VARCHAR (100),
    PRIMARY KEY ([KEY])
)

The table allows to keep key-value pairs for each configuration members.

The below example illustrates how to define and use this section to consume the configuration values. Declare ChoSqlServerConfigurationSectionAttribute to the class to use this section handler.

Listing 4.6.2 Defining Configuration Object

[ChoSqlServerConfigurationSection("appSettings", 
@"Server=SNYC12345400\XYZKND01;Database=TestDb;Trusted_Connection=True;", "APP_SETTINGS")]
public class AppSettings : ChoConfigurableObject
{
    [ChoPropertyInfo("name")]
    public string Name;

    [ChoPropertyInfo("address", DefaultValue = "100, Madison Avenue, New York, NY 10010")]
    public string Address;
}

The code above illustrates how the sqlserver configuration section is specified to configuration object. In here, we specified configSectionName, database connection string and table name. TableName is optional. If not specified, framework will try to look for tablename in the name of configuration section object name (AppSettings).

Once you instantiate an object, you are ready to consume the configuration values. The file below shows the layout of the configuration file produced when using this section handler.

Listing 4.6.3 HelloWorld.xml

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="appSettings" type="Cinchoo.Core.Configuration.ChoDictionarySectionHandler, 
    Cinchoo.Core" />
  </configSections>
  <appSettings cinchoo:configObjectAdapterType=
    "Cinchoo.Core.Configuration.ChoDbGenericKeyValueConfigStorage, Cinchoo.Core" 
    xmlns:cinchoo="http://schemas.cinchoo.com/cinchoo/01/framework">
    <cinchoo:configObjectAdapterParams 
    xmlns:cinchoo="http://schemas.cinchoo.com/cinchoo/01/framework">
    <![CDATA[CONNECTION_STRING='Server=WNPCTDVZKN01\MSZKND01;Database=School;
    Trusted_Connection=True;';TABLE_NAME=APP_SETTINGS;PROVIDER_NAMESPACE=System.Data.SqlClient]]>
    </cinchoo:configObjectAdapterParams>
  </appSettings>
</configuration>

Number of ChoSqlServerConfigurationSectionAttribute overloads available to meet different requirements. Most of them are self explanatory. One important overload mentioned below now accepts .NET ConnectionString name as parameter.

Listing 4.6.4 ChoSqlServerConfigurationSectionAttribute Overload

public ChoSqlServerConfigurationSectionAttribute
    (string configElementPath, string connectionStringOrName, string tableName);

For example, if your application is already using database using .NET ConnectionString, you might see the below entries in the application configuration file.

Listing 4.6.5 App.Config file

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
    </configSections>
    <connectionStrings>
        <add name="TESTDB"
            connectionString="Server=SNYC12345400\XYZKND01;Database=TestDb;
        Trusted_Connection=True;" providerName ="System.Data.SqlClient"/>
    </connectionStrings>
</configuration>

This configuration section leverages this feature by accepting .NET ConnectionString name via parameter to eliminate the duplication of maintaining database connection string in multiple places.

The code below illustrates how to use the above connection string name in configuration object.

Listing 4.6.6 Configuration Object using ConnectionStringName

[ChoSqlServerConfigurationSection("appSettings", @"TESTDB", "APP_SETTINGS")]
public class AppSettings : ChoConfigurableObject
{
    [ChoPropertyInfo("name")]
    public string Name;

    [ChoPropertyInfo("address", DefaultValue = "100, Madison Avenue, New York, NY 10010")]
    public string Address;
}

Cinchoo framework automatically discovers the connection string from system ConnectionStrings section seamlessly and uses them for consuming configuration values.

4.7 ChoAnyDbConfigurationSection

It handles the reading and writing of configuration values from any database. All you need is the ADO.NET driver for the database you want to work with. This section handler allows multiple applications to store and consume centrally located configuration values.

First and foremost, you must create a configuration table in the targeted database as per the below schema.

Listing 4.6.1 Configuration table

CREATE TABLE APP_SETTINGS
(
    [KEY] VARCHAR (50) NOT NULL,
    VALUE VARCHAR (100),
    PRIMARY KEY ([KEY])
)

The table allows to keep key-value pairs for each configuration members.

The below example illustrates how to define and use this section to consume the configuration values. Declare ChoAnyDbConfigurationSectionAttribute to the class to use this section handler.

Listing 4.6.2 Defining Configuration Object

[ChoAnyDbConfigurationSection("appSettings", @"Data Source=.\SqliteTest.db;Version=3;
    Pooling=True;Max Pool Size=100;", "APP_SETTINGS", "System.Data.SQLite")]
public class AppSettings : ChoConfigurableObject
{
    [ChoPropertyInfo("name")]
    public string Name;

    [ChoPropertyInfo("address", DefaultValue = "100, Madison Avenue, New York, NY 10010")]
    public string Address;
}

The code above illustrates how to setup the configuration section to use Sqlite database to the configuration object. In here, we specified configSectionName, sqlite database connection string, provideName and tableName.

ProvideName is the database ADO.NET provide name. This parameter is optional. If not specified, ‘System.Data.SqlClient‘ will be used.

TableName is optional. If not specified, framework will try to look for tablename in the name of configuration section object name (AppSettings).

Once you instantiate an object, you are ready to consume the configuration values. The file below shows the layout of the configuration file produced when using this section handler.

Listing 4.6.3 HelloWorld.xml

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="appSettings" type="Cinchoo.Core.Configuration.ChoDictionarySectionHandler, 
    Cinchoo.Core" />
  </configSections>
  <appSettings cinchoo:configObjectAdapterType=
    "Cinchoo.Core.Configuration.ChoDbGenericKeyValueConfigStorage, Cinchoo.Core" 
    xmlns:cinchoo="http://schemas.cinchoo.com/cinchoo/01/framework">
    <cinchoo:configObjectAdapterParams 
    xmlns:cinchoo="http://schemas.cinchoo.com/cinchoo/01/framework">
    <![CDATA[CONNECTION_STRING='Server=WNPCTDVZKN01\MSZKND01;Database=School;
    Trusted_Connection=True;';TABLE_NAME=APP_SETTINGS;PROVIDER_NAMESPACE=System.Data.SqlClient]]>
    </cinchoo:configObjectAdapterParams>
  </appSettings>
</configuration>

ChoDbAnyConfigurationSectionAttribute now accepts .NET ConnectionString name as parameter via connectionStringOrName.

For example, if your application is already using database using .NET ConnectionString, you might see the below entries in the application configuration file.

Listing 4.6.5 App.Config file

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
    </configSections>
    <connectionStrings>
        <add name="TESTDB"
            connectionString="Server=SNYC12345400\XYZKND01;Database=TestDb;
        Trusted_Connection=True;" providerName ="System.Data.SqlClient"/>
    </connectionStrings>
</configuration>

This configuration section leverages this feature by accepting .NET ConnectionString name via parameter to eliminate the duplication of maintaining database connection string in multiple places.

The code below illustrates how to use the above connection string name in configuration object.

Listing 4.6.6 Configuration Object using ConnectionStringName

[ChoAnyDbConfigurationSection("appSettings", @"TESTDB", "APP_SETTINGS")]
public class AppSettings : ChoConfigurableObject
{
    [ChoPropertyInfo("name")]
    public string Name;

    [ChoPropertyInfo("address", DefaultValue = "100, Madison Avenue, New York, NY 10010")]
    public string Address;
}

Cinchoo framework automatically discovers the connection string and provides name from system ConnectionStrings section seamlessly and uses them for consuming configuration values.

It is very simple to work with configuration using Cinchoo framework. Try for yourself. Thanks.

Advertisement

9 thoughts on “Cinchoo – Application configuration made easy

  1. What happens if I want to use and have the config in an assembley – wheres the best place to instantiate and shutdown e.g. ChoFramework.Shutdown();

  2. Best place to call ChoFramework.Shutdown() is AppDomain.ProcessExit()

    Here is the sample code:

    AppDomain.CurrentDomain.ProcessExit += ((sender, e) => ChoFramework.Shutdown());

    1. Thanks Raj.
      The one other thing that I was worried about was how slow it was initialising. We have emergency services applications where we need quick start up and responses. Is there any way to improve the startup time on the first call to a settings class.

      1. You will have to eager initialize the Cinchoo framework at some point during your application start-up by calling ChoFramework.Initialize(). This will reduce the time to initialize the settings class for the first time. Hope this helps. Let me know if you need any help. Thanks.

  3. Your framework is brilliant. I’m slightly disappointed by the startup and shutdown time (what is your library doing there?), but your configuration library worked like magic, so it’s worth it. I didn’t actually expect it to serialize my “Point LastWindowLocation” setting on form close and read it from a String, but it did.

    1. Can you please post me the startup and shutdown time? Let me have a look and see if there is anything can be done. Also I will take a look at it from my side as well. Thanks for your feedback.

      1. Sorry I’m not gonna profile it but….it seems to be around 2-3 full seconds for both starting up and shutting down. Which is bearable, just not preferable. Is there were any way we could disable unnecessary features in the framework? Could you also set your thread to IsBackground so that it automatically exits when our app does? That way we don’t have to call .Shutdown()? But maybe then you can’t dispose resources cleanly.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s