Click here to Skip to main content
15,885,244 members
Articles / Programming Languages / C#
Article

Configuration Files for Class Library Projects

Rate me:
Please Sign up or sign in to vote.
2.64/5 (7 votes)
8 Mar 2007CPOL3 min read 82.9K   614   17   10
This article explains how we can create a custom ConfigurationManager for DLL assemblies (created with .NET 1.1) that can load configuration settings from an XML based configuration file.
Screenshot - screen_main.jpg

Introduction

While working with Windows Forms and web form applications in .NET 1.1, we realize that we can easily load application settings from configuration files. .NET configuration architecture made it very easy to load these files and read them in the application at runtime. But there are times when we develop complex business components and those must have their own configuration related data. Since these library components are independent of applications in which they are loaded, it makes sense that these components must have their own ConfigurationManager. This article explains how we can develop Configuration Manager for a DLL. I have got inspiration from .NET 2.0 configuration architecture and tried to make this manager class exactly the same as in Framework 2.0. Those readers who haven't used ConfigurationManager and WebConfigurationManager provided by .NET 2.0 are encouraged to read the background section of this article.

Background

Since structure of the code in this article revolves around the configuration architecture present in Framework 1.1 and 2.0, it's better to understand first how to read config files in both versions of the Framework.

Framework 1.1

XML
<!-- app.config -->

<configuration>
    <configSections>
        <section name="MyTempSection"
		type="System.Configuration.SingleTagSectionHangler" />
        <section name="CustomSection1"
		type="System.Configuration.DictionarySectionHandler" />
    </configSections>

    <MyTempSection amount="7500" currency="USD" />
    <customSection1>
        <add key="name" value="Muhammad" />
        <add key="lastName" value="Irfan" />
    </customSection1>

</configuration>
//To read above configuration sections we can use the following code:

IDictionary section = System.Configuration.ConfigurationSettings.GetConfig
	("MyTempSection") as IDictionary
String amount = section["amount"] ;
String currency = section["currency"];

IDictionary section1 = System.Configuration.ConfigurationSettings.GetConfig
	("CustomSection1") as IDictionary;

String name = (string) section1"name"];
String lastName = (string) section1["lastName"]

For section type in app.config, I have used SingleTagSectionHandler and DictionarySectionHandler just to make the example clear. If you want to load config data into your own type, then you can declare a custom type by implementing IConfigurationSectionHandler. SingleTagSectionHandler specifies the configuration settings as key value pairs using XML Attributes and DictionarySectionHandler allows the configuration information to be specified as name value pairs in XML nodes. In .NET 2.0 configuration architecture is much more simplified and enhanced. Framework 2.0 contains WebConfigurationManager & ConfigurationManager that are core to this architecture. ConnectionStrings property has been added that retrieves ConnectionStringSection. By using connnectionStringSection, we can get connectionStringSettingsCollection and enumerate all attributes for that section. The following code demonstrates how to use custom config sections.

Framework 2.0

XML
<!-- app.config -->
<configuration>
    <configSections>
        <sectionGroup name="MySectionGroup">
            <section name="settings" type="[NameSpace].[Class_Name], [AssemblyName]" />
        </sectionGroup>
    </configSections>

    <MySectionGroup>
        <settings dbProvider="System.Data.SqlClient" dbName="SPR01" />
    </MySectionGroup>
</configuration>
//Once again to read the above section we can use the following code
System.Configuration.Configuration webConfig =
	System.Configuration.ConfigurationManager.OpenExeConfiguration
	(ConfigurationUserLevel.PerUserRoamingAndLocal);
Test_Desktop_2005.MyCustomConfigurationHandler config =
	(Test_Desktop_2005.MyCustomConfigurationHandler)webConfig.GetSection
	("MySectionGroup/settings");

string dbProvider = config.DBProvider;
string dbName = config.DBName;

// Class that creates the configuration handler
public class MyCustomConfigurationHandler : ConfigurationSection
{
    // Empty Construct
    public MyCustomConfigurationHandler() { }
    // Loaded Construct
    public MyCustomConfigurationHandler(string dbProvider, string dbName)
    {
        DBProvider = dbProvider;
        DBName = dbName;
    }

    // First Number Property
    [System.Configuration.ConfigurationProperty("dbProvider",
	DefaultValue = "", IsRequired = true, IsDefaultCollection = false)]
    public string DBProvider
    {
        get
        {
            return (string)this["dbProvider"];
        }
        set
        {
            this["dbProvider"] = value;
        }
    }

    // Second Number Property
    [System.Configuration.ConfigurationProperty("dbName",
	DefaultValue = "", IsRequired = true, IsDefaultCollection = false)]
    public string DBName
    {
        get
        {
            return (string)this["dbName"];
        }
        set
        {
            this["dbName"] = value;
        }
    }
} 

Using the Code

Attached is the demo project which shows how to use the ConfigurationManager class efficiently. We will use an XML file Configuration.xml as a configuration file. In the project, you can browse and locate the file. If you have a look at the code, you will come to know that using our ConfigurationManager is the same as using ConfigurationManager in .NET 2.0. It contains methods with the same name and parameters. For loading XML file, I have used XPathNavigator because it doesn't build a node tree like XmlDocument and XmlNode; rather it only looks at one node at a time. It builds the nodes when you move to them. It doesn't use as much memory because it doesn't create the entire node tree in the beginning. It creates the tree dynamically as you move through the file.

XML
<!-- Configuration.xml -->
<configuration>
    <cofigSection>
        <globalThreshold amount="7500" currency="7500" />
        <general>
            <add key="key1" value="value1" />
            <add key="key2" value="value2" />
            <add key="key3" value="value3" />
            <add key="key4" value="value4" />
        </general>
    </cofigSection>

    <connectionStrings>
        <add name="connection1" connectionString="connection_string_for_connection_1"
		provider="System.Data.SqlClient" />
        <add name="connection2" connectionString="connection_string_for_connection_2"
		provider="System.Data.Oledb" />
    </connectionStrings>

    <appSettings>
        <add key="WindowState" value="Maximized" />
    </appSettings>

</configuration> 

ConfigurationManager has one pubic method, i.e. OpenExeConfiguration. It takes the config file path and returns configuration object.

C#
ConfigurationManager manager = new ConfigurationManager();
Configuration configuration = manager.OpenExeConfiguration
				(this.openFileDialog1.FileName);

Once we have got the configuration object, we can directly access appSetting and connectionString values by using the relevant properties it provides. The LoadSingleSection() method loads a single section from connection string sections collection by using the name of that section. ConnectionStringsSettingsCollection implements IDictionary so it becomes easy to access node attributes using famous operator []. The following code demonstrates that:

C#
NameValueCollection appSettingCollection = configuration.AppSettings.Settings;
string windowState = appSettingCollection["WindowState"];

ConnectionStringSection connectionStringSection = configuration.ConnectionStrings;
ConnectionStringsSettingsCollection sectionCollection =
	connectionStringSection.LoadSingleSection("connection1");

string connectinString = sectionCollection["connectionString"]);
string connectionName = sectionCollection["name"]);
string dbProvider = sectionCollection["provider"]);

We can also read custom sections from our configuration.xml using GetSection() method of configuration object. Another important method of this manager class is GetAllChildsOfSection() which returns all child nodes of a section. The purpose to include this method is that it gives us <add> nodes and their key value pairs of a specific section. It works just like AppSettings property of configuration which returns key value of <AppSetting> section. The following code snippet shows how to use both GetSection() and GetAllChildsOfSection() methods.

C#
ConfigurationSection customSection = configuration.GetSection("globalThreshold");
string amount = customSection["amount"];

NameValueCollection generalConfigurationsCollection =
	configuration.GetAllChildsOfSection("//cofigSection/general");

Though we have used OpenFileDialog to location the file, in real scenario where component/class library would be used by web/windows form application,
we can put configuration.xml in the same directory from where the component will be loaded.

C#
Configuration configuration = manager.OpenExeConfiguration
	(System.AppDomain.CurrentDomain.BaseDirectory+@"Configuration.xml"); 

History

  • 8th March, 2007: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) The Hiring Solutions Company
Pakistan Pakistan
Irfan is currently working as a Systems Analyst with one of the largest E-Recruitment solutions provider in the ME region. He has been in the Software industry for 5 years now. He started his careers with C++ and VB, slowly moved onto open source development (LAMP) and now consistently working on all Microsoft technologies. He specializes in .NET and loves to work on lightweight platforms/tools like JavaScript, XHTML, HTML, JQuery etc. He believes in changing his course of development as the technology advances. You can reach him on his blog (http://irfaann.blogspot.com) where he shares his views and experiences with software design and development.

Comments and Discussions

 
GeneralMy vote of 2 Pin
ashkan.zamani15-May-12 21:35
ashkan.zamani15-May-12 21:35 
GeneralNot so fast Pin
Not Active8-Mar-07 11:43
mentorNot Active8-Mar-07 11:43 
GeneralRe: Not so fast Pin
m_irfan9-Mar-07 5:59
m_irfan9-Mar-07 5:59 
GeneralRe: Not so fast Pin
Not Active9-Mar-07 6:58
mentorNot Active9-Mar-07 6:58 
GeneralRe: Not so fast Pin
m_irfan9-Mar-07 10:45
m_irfan9-Mar-07 10:45 
GeneralRe: Not so fast Pin
Not Active9-Mar-07 16:53
mentorNot Active9-Mar-07 16:53 
GeneralRe: Not so fast Pin
m_irfan9-Mar-07 21:33
m_irfan9-Mar-07 21:33 
QuestionRe: Not so fast Pin
frblondin11-Mar-07 1:22
frblondin11-Mar-07 1:22 
AnswerRe: Not so fast Pin
m_irfan11-Mar-07 2:26
m_irfan11-Mar-07 2:26 
GeneralRe: Not so fast Pin
frblondin11-Mar-07 7:03
frblondin11-Mar-07 7:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.