Contents
Cinchoo is the application framework for .NET. One of the main functionalities it provides to the users is application configuration management. Application configuration is the information that application reads and/or writes at run-time from the source.
Cinchoo framework simplifies the development 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.
Cinchoo configuration framework has the following powerful features:
- One single API to deal with configuration data with multiple sources
- Two-way, type-safe configuration management
- Create the configuration files, if 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 is missing any entries in the configuration files
This configuration library is written in C# for the .NET 4.0 Framework. It is part of Cinchoo framework, an application framework for .NET with lot of features like Configuration Management, common ApplicationHost, Shell features, etc.
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
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;
}
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 'name
' as 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 'address
' as 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 as simple as constructing instance of it. Sample code below shows how to use it.
Listing 3.2 Main Method
static void Main(string[] args)
{
AppSettings appSettings = new AppSettings();
Console.WriteLine(appSettings.ToString());
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
="1.0"="utf-8"
<configuration>
<configSections>
<section name="appSettings" type="Cinchoo.Core.Configuration.ChoNameValueSectionHandler, Cinchoo.Core" />
</configSections>
<appSettings>
<add key="name" value="Raj" />
<add key="address" value="100, Madison Avenue, New York, NY 10010" />
</appSettings>
</configuration>
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. ChoSqlServerConfigurationSection
- Read/Write configuration values from MS SqlServer database. ChoDbGenericKeyValueConfigurationSection
- Read/Write configuration values from any databases. ChoJSONConfigurationSection
- Read/Write JSON formatted configuration values.
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. If you need a configuration to be efficient, use ChoDictionaryConfigurationSection
handler.
The below example illustrates how to define configuratrion object using 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
="1.0"="utf-8"
<configuration>
<configSections>
<section name="appSettings" type="Cinchoo.Core.Configuration.ChoNameValueSectionHandler, Cinchoo.Core" />
</configSections>
<appSettings>
<add key="name" value="Raj" />
<add key="address" value="100, Madison Avenue, New York, NY 10010" />
</appSettings>
</configuration>
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 configuration object using 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
="1.0"="utf-8"
<configuration>
<configSections>
<section name="appSettings" type="Cinchoo.Core.Configuration.ChoDictionarySectionHandler, Cinchoo.Core" />
</configSections>
<appSettings>
<add key="name" value="Raj" />
<add key="address" value="100, Madison Avenue, New York, NY 10010" />
</appSettings>
</configuration>
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 in xml attributes.
The below example illustrates how to define configuration object using 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
="1.0"="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>
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 still 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 handler simplifies the consumption of INI file values into configuration object by providing unified interface. The below example illustrates how to define configuration object using 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 control values are maintained in the configuration file for you to tweak them later on.
Listing 4.4.3 HelloWorld.xml
="1.0"="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>
Dynamic / Runtime setup
Cinchoo provides way to setup the ini file at run-time as well, in cases where the ini file is determined dynamically during execution time like via command line parameter etc.
The sample below shows how to achieve it
[ChoIniConfigurationSection("appIniSettings", "SAMPLE", "Test.ini")]
public class AppSettingsIni : ChoConfigurableObject
{
[ChoPropertyInfo("name")]
public string Name;
[ChoPropertyInfo("address")]
public string Address;
protected override void OnAfterConfigurationObjectLoaded()
{
Console.WriteLine(ToString());
}
protected override void OverrideMetaDataInfo(ChoBaseConfigurationMetaDataInfo metaDataInfo)
{
ChoIniConfigurationMetaDataInfo mi = metaDataInfo as ChoIniConfigurationMetaDataInfo;
mi.IniFilePath = "TestOverride.ini";
base.OverrideMetaDataInfo(metaDataInfo);
}
}
Simply override the 'OverrideMetaDataInfo' method and send the ini file path at run-time to load it.
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
- HKCU -
HKEY_CURRENT_USER
- HKLM -
HKEY_LOCAL_MACHINE
- HKCR -
HKEY_CLASSESS_ROOT
- HKCC -
HKEY_CURRENT_CONFIG
Once you instantiate an object, you are ready to consume the configuration values. The file below shows the control values kept to modify them later on if needed.
Listing 4.5.3 HelloWorld.xml
="1.0"="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>
Dynamic / Runtime setup
Cinchoo provides way to setup the ini file at run-time as well, in cases where the ini file is determined dynamically during execution time like via command line parameter etc.
The sample below shows how to achieve it
[ChoRegistryConfigurationSection("appSettings", @"HKCU\Software\HelloWorld")]
public class AppSettingsRegistry : ChoConfigurableObject
{
[ChoPropertyInfo("name")]
public string Name;
[ChoPropertyInfo("address")]
public string Address;
protected override void OnAfterConfigurationObjectLoaded()
{
Console.WriteLine(ToString());
}
protected override void OverrideMetaDataInfo(ChoBaseConfigurationMetaDataInfo metaDataInfo)
{
ChoRegistryConfigurationMetaDataInfo mi = metaDataInfo as ChoRegistryConfigurationMetaDataInfo;
mi.RegistryKey = @"HKCU\Software\HelloWorldNew";
base.OverrideMetaDataInfo(metaDataInfo);
}
}
Simply override the 'OverrideMetaDataInfo' method and send the ini file path at run-time to load it.
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
="1.0"="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[
</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
="1.0"="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.
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.7.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.7.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.7.3 HelloWorld.xml
="1.0"="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[
</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.7.5 App.Config file
="1.0"="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.7.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 handles the reading and writing of configuration values from JSON formatted file, a simple JavaScript Object Notation readable format for structuring data. Majority of the latest platforms consume data in this format.
Listing 4.8.1 Sample JSON file (AppSettings.json)
{"name":"Mark","address":"10 River Road, NewCity, 08837"}
PS: This section handler is not part of the Cinchoo framework library. You need install the plug-in from nuget in order to use it in your project.
Install-Package Cinchoo.Core.Configuration.JSON
This section handler simplifies the consumption of JSON file values into configuration object by providing unified interface. The below example illustrates how to define configuration object using this section to consume the JSON values. Declare ChoJSONConfigurationSectionAttribute
to the configuration class to use this section handler.
Listing 4.8.2 Defining Configuration Object
[ChoJSONConfigurationSection("appSettings", ConfigFilePath = "appsettings.json")]
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 JSON configuration section is specified to configuration object. It specifies the name of the JSON file (AppSettings.json) 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 JSON file not exists, it will be created automatically, containing all the configuration members with default values.
Once you instantiate an object, you are ready to consume the configuration values.
Listing 4.8.3 Main method
static void Main(string[] args)
{
AppSettings applicationSettings = new AppSettings();
Console.WriteLine(applicationSettings.Name);
ChoConsole.PauseLine();
}
Dynamic / Runtime setup
Cinchoo provides way to setup the ini file at run-time as well, in cases where the ini file is determined dynamically during execution time like via command line parameter etc.
The sample below shows how to achieve it
[ChoJSONConfigurationSection("appSettings", ConfigFilePath = "test.json", Silent = false)]
public class AppSettings : ChoConfigurableObject
{
[ChoPropertyInfo("name", DefaultValue = "Raj")]
[ChoNotNullOrWhiteSpaceValidator]
public string Name
{
get;
set;
}
[ChoPropertyInfo("address", DefaultValue = "10 River Road, 08837")]
public string Address;
[ChoPropertyInfo("Date", DefaultValue = "%%NOW^MM/dd/yyyy HH:mm:ss%%")]
public DateTime Date;
protected override void OnAfterConfigurationObjectLoaded()
{
Console.WriteLine(ToString());
}
protected override void OverrideMetaDataInfo(ChoBaseConfigurationMetaDataInfo metaDataInfo)
{
ChoStandardConfigurationMetaDataInfo mi = metaDataInfo as ChoStandardConfigurationMetaDataInfo;
mi.ConfigFilePath = "test12.json";
base.OverrideMetaDataInfo(metaDataInfo);
}
}
It is very simple to work with configuration using Cinchoo framework. Try for yourself. Thanks.