Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Configuration Files for Class Library Projects

0.00/5 (No votes)
8 Mar 2007 1  
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

<!-- 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

<!-- 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.

<!-- 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.

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:

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.

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.

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

History

  • 8th March, 2007: Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here