[ Team LiB ] |
15.2 Adding Your Own Configuration SettingsThere are two ways to add your own configuration settings to the configuration files. You can use the appSettings configuration section, which the .NET Framework knows how to interpret automatically, or you can add your own configuration section and write the code for the framework to access it. 15.2.1 Using the appSettings ElementThe easiest way to add configuration settings to a configuration file is to use the appSettings element. Configuration settings added this way take the form of key-value pairs. These key-value pairs may be added anywhere in the hierarchy of configuration files. Once added, key-value pairs can be removed individually in a configuration file lower in the hierarchy, or the entire set can be cleared. Example 15-1 shows an excerpt from a machine configuration file, with an appSettings element added. Example 15-1. Excerpt from the machine configuration file<?xml version="1.0" encoding="UTF-8" ?> <configuration> ... <appSettings> <add key="some key" value="some value" /> </appSettings> ... </configuration> This configuration file simply adds a configuration setting whose key is "some key" and whose value is "some value". The added key will be available to all .NET applications running on this machine. Example 15-2 shows an application configuration file that uses the appSettings element to remove the key added in the machine configuration file and add another key. Example 15-2. The application configuration file<?xml version="1.0" encoding="UTF-8" ?> <configuration> <appSettings> <remove key="some key" /> <add key="some other key" value="some other value" /> </appSettings> </configuration> The application that loads this application configuration file will no longer have the key-value pair with key "some key", but it will have a key-value pair with key "some other key". The application configuration file can also use the clear element to remove all the appSettings key-value pairs. The key-value pairs are accessed using the System.Configuration.ConfigurationSettings class. Example 15-3 shows how you can access the key-value pairs defined in Examples Example 15-1 and Example 15-2. Example 15-3. Program to read and display app settingsusing System; using System.Configuration; public class AppSettingsTest { public static void Main(string [ ] args) { string someKey = "some key"; string someOtherKey = "some other key"; Console.WriteLine("\"{0}\"=\"{1}\"", someKey, ConfigurationSettings.AppSettings[someKey]); Console.WriteLine("\"{0}\"=\"{1}\"", someOtherKey, ConfigurationSettings.AppSettings[someOtherKey]); } } Running the AppSettingsTest executable, you can expect to see the following output: "some key"="" "some other key"="some other value" That's fine, if you're only interested in string values. If you need to retrieve a different type of data, however, you can use the AppSettingsReader class. AppSettingsReader has only one method, GetValue( ), which takes as parameters the key name and the Type of data you wish to have returned. For example, take the following appSettings element: <appSettings> <add key="some numeric key" value="5.00987" /> </appSettings> To return that value as a decimal, you would use the following code: AppSettingsReader reader = new AppSettingsReader( ); decimal value = (decimal)reader.GetValue("some numeric key",typeof(decimal));
15.2.2 Custom ElementsThe appSettings element is actually a special case of the general mechanism for adding custom configuration elements, called the configuration section. A configuration section is simply an element in a configuration file. The ConfigSettings class knows how to read an arbitrary configuration section because you add a configSection element to the configuration file to tell it how. The appSettings configuration section is defined in the machine configuration file, as shown below: <section name="appSettings" type="System.Configuration.NameValueFileSectionHandler, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> I'll explain more about the section element in a moment. You can see, though, that the section element shows us that the appSettings section is handled by the System.Configuration.NameValueFileSectionHandler type. This type's Create( ) method reads the XML that is passed to it as an XmlNode, and creates the System.Collections.Specialized.NameValueCollection that is eventually returned by the ConfigSettings.AppSettings property. The steps to create your own custom configuration sections are as follows:
15.2.2.1 Choosing a configuration section handlerThe IConfigurationSectionHandler interface requires only one method, Create( ), which returns an object containing the configuration section's settings in a useful form. This object will be returned by ConfigurationSettings.GetConfig( ). The .NET Framework includes five built-in configuration section handlers, which are listed below:
For some purposes, none of the built-in configuration section handlers may be appropriate. In that case, you can write your own handler by implementing IConfigurationSectionHandler. This interface has only method to implement, Create( ). One of Create( )'s parameters is the XmlNode containing the configuration section element itself. Perhaps the simplest custom section handler would just return the XML used to construct the configuration section. Example 15-4 shows an implementation of XmlSectionHandler that does that. Example 15-4. A simple implementation of XmlSectionHandlerusing System; using System.Configuration; using System.Xml; public class XmlSectionHandler : IConfigurationSectionHandler { public object Create(object parent, object configContext, XmlNode section) { return section; } } If you use this XmlSectionHandler, you'll see that the Create( ) returns an instance of System.Configuration.XmlConfigElement, which is an undocumented subclass of XmlElement. You shouldn't care what concrete type it is, as long as you treat it as an XmlElement. 15.2.2.2 Defining the configuration sectionOnce you've selected or written a configuration section handler, you need to define the configuration section and tell the configuration system of how to deal with it. To do this, you add a section element to the configuration file's configSections element. The section elements define how a configuration section is to be handled. The section element has two attributes, name and type. The name attribute matches the name of a configuration section element that appears in a configuration file, and the type attribute specifies the name of the IConfigurationSectionHandler instance that will handle the configuration section. section elements may be organized into a hierarchy using section groups. The element that defines section groups is called, appropriately, sectionGroup, and its only attribute is name. You can nest as many sectionGroup elements as you want, and a sectionGroup may contain both section elements and other sectionGroup elements. Example 15-5 shows the configSections element of an application configuration file using the XmlSectionHandler in a configuration section group. Example 15-5. Application configuration using an XmlSectionHandler in a configuration section group<configSections> <sectionGroup name="Group"> <section name="Custom" type="XmlSectionHandler, AppSettingsTest" /> </sectionGroup> </configSections>
15.2.2.3 Adding the configuration sectionThe next step is to add the configuration section itself to the configuration file. Because of the way I wrote the XmlSectionHandler, it will accept any XML content. The only restriction on how it's used in the configuration file is that it must appear in the section group as defined in Example 15-5. Example 15-6 shows the complete application configuration file containing the configSections element, the Custom element I defined in the configSections element, and the appSettings element from Example 15-2. Example 15-6. Complete application configuration file<?xml version="1.0" encoding="UTF-8" ?> <configuration> <configSections> <sectionGroup name="Group"> <section name="Custom" type="XmlSectionHandler, AppSettingsTest" /> </sectionGroup> </configSections> <appSettings> <remove key="some key" /> <add key="some other key" value="some other value" /> <add key="some numeric key" value="5.00987" /> </appSettings> <Group> <Custom> <someElement attribute="attribute1">some content & stuff <![CDATA[Some <text> that the parser won't even try to parse ]]> </someElement> </Custom> </Group> </configuration>
15.2.2.4 Reading the custom configuration programmaticallyNow you're ready to actually use the configuration data in the application configuration file. You already know how to access configuration settings in the appSettings section using ConfigurationSetting.AppSettings property. You can also access them using the ConfigurationSettings.GetConfig( ) method. The only parameter to GetConfig( ) is a string containing the path to the configuration section you want to get.
Example 15-7 shows a program that gets configuration settings from the appSettings and Custom configuration sections. Example 15-7. Reading various configuration information programmaticallyusing System; using System.Configuration; using System.Xml; public class AppSettingsTest { public static void Main(string [ ] args) { try { string someKey = "some key"; Console.WriteLine("{0}={1}", someKey, ConfigurationSettings.AppSettings[someKey]); string someOtherKey = "some other key"; Console.WriteLine("{0}={1}", someOtherKey, ConfigurationSettings.AppSettings[someOtherKey]); string someNumericKey = "some numeric key"; AppSettingsReader reader = new AppSettingsReader( ); Console.WriteLine("{0}={1}", someNumericKey, reader.GetValue(someNumericKey,typeof(decimal))); Console.WriteLine( ); string custom = "Group/Custom"; XmlNode customConfig = (XmlNode)ConfigurationSettings.GetConfig(custom); Console.WriteLine("{0}={1}", custom, customConfig); Console.WriteLine("{0}={1}", customConfig.Name, customConfig.InnerXml); } catch (Exception e) { Console.Error.WriteLine(e); } } } public class XmlSectionHandler : IConfigurationSectionHandler { public object Create(object parent, object configContext, XmlNode section) { return section; } } Running this program, you'll see the following output: some key= some other key=some other value some numeric key=5.00987 Group/Custom=System.Configuration.ConfigXmlElement Custom=<someElement attribute="attribute1">some content & stuff <![CDATA[Some <text> that the parser won't even try to parse ]]></someElement> When calling ConfigurationSettings.GetConfig( ), you are responsible for knowing what type of object is being returned by the configuration section handler. If you cast the returned object to an incompatible type, an InvalidCastException will be thrown. It's particularly important to be aware of return types if you try to use NameValueSectionHandler and DictionarySectionHandler interchangeably. Although both handlers will happily read the same XML from the configuration file, NameValueSectionHandler returns a NameValueCollection, while DictionarySectionHandler returns a Hashtable. |
[ Team LiB ] |