Creating New Configuration Sections

The <appSettings> section is one of many predefined configuration sections provided by the .NET Framework. Programmers can also create their own sections. To create a new section, you need to accomplish two basic tasks: declare the section in the <configSections> block, and fill the section with custom data.

One of the key bits of information you need to specify while declaring a new section is the name of the section handler class. The section handler class can be one of the predefined classes provided by the .NET Framework or a class that you write from scratch or inherit from an existing class. The section handler object is responsible for reading and parsing the actual contents of the setting.

Declaring a New Section

The <configSections> node contains the declarations of all the sections in the various configuration files. The predefined sections are declared in the machine.config file that the .NET Framework installs. Custom sections must be registered by the application that plans to use them. The application’s configuration file is a good place for inserting this information.

The <configSections> node can accept up to four child nodes: <section>, <sectionGroup>, <remove>, and <clear>. The <remove> element removes a previously defined section, or a section group, from the <configSections> block. The <clear> element clears all previously defined sections and section groups.

Note

The <remove> and <clear> elements don’t affect the actual data stored in the configuration file. Removing a section doesn’t erase the related data from the file, but the data becomes unreachable because of the missing section declaration.


A new section is registered using the <section> element. As mentioned, the name attribute of this element specifies the name of the section and the type attribute specifies the name of the section handler class. The name of the configuration section class should contain full assembly information, including version, culture, and public key token, if any. All the predefined handlers are defined in the same assembly and therefore share the same information, as in the following example:

System, Version=1.0.3300.0, Culture=neutral,   
   PublicKeyToken=b77a5c561934e089

Note

When you create a custom assembly with no strong name (a strong name is necessary if you want to put the assembly in the global assembly cache), the version number is defined in the assemblyinfo file that Microsoft Visual Studio .NET automatically adds to the project. The culture is neutral, and the public key token is null. Here’s an example:

AppSettings_CS, Version=1.0.9.0, Culture=neutral, 
   PublicKeyToken=null


The custom section follows the <configSections> block and contains the actual configuration settings. The following code creates a new section named userPreferences that accepts name/value pairs:

<configuration>
   <configSections>
      <section name="userPreferences" 
         type="System.Configuration.NameValueFileSectionHandler, Œ 
            System, Version=1.0.3300.0, Culture=neutral, Œ
            PublicKeyToken=b77a5c561934e089" />
   </configSections>
   <userPreferences>
      <add key="ReleaseDate" value="10-9-02" />
   </userPreferences>
</configuration>

Sections can be grouped under a <sectionGroup> element. Declaring a section group creates a namespace and ensures that no naming conflicts arise with other configuration sections defined by someone else. Section groups can also be nested within each other. The following code snippet declares the userPreferences section nested in the AppName group:

<sectionGroup name="AppName">
   <section name="userPreferences" 
      type="System.Configuration.NameValueSectionHandler, Œ 
         system, Version=1.0.3300.0, Culture=neutral, Œ
         PublicKeyToken=b77a5c561934e089" />
</sectionGroup>

A node with the group name must also wrap the settings subtree, as shown here:

<AppName>
   <userPreferences>
      <add key="ReleaseDate" value="10-9-02" />
   </userPreferences>
</AppName>

To read the settings of a custom section, you use the GetConfig method, passing the fully qualified name of the section to retrieve. For example, the following code returns the settings in the <userPreferences> section:

NameValueCollection settings;
settings = ConfigurationSettings.GetConfig("AppName/userPreferences");
MessageBox.Show(setting["ReleaseDate"]);

Note

A new section, or section group, that is defined in the machine.config file is visible to all applications. This setting can be changed using the allowDefinition attribute for ASP.NET applications only. In contrast, sections defined in the application configuration file are visible only to the local application.


Types of Section Handlers

A section handler is a .NET Framework class that implements the IConfigurationSectionHandler interface. It interprets and processes the configuration settings stored in a configuration section and returns a configuration object based on the configuration settings. The returned object is accessed by the GetConfig method. The data type returned by the GetConfig method depends on the section handler defined for the particular section.

The .NET Framework provides a few predefined section handlers, listed in Table 15-2. All of these section handlers belong to the System.Configuration namespace and are implemented in the System assembly.

Table 15-2. Predefined Section Handlers
Class Description
DictionarySectionHandler Reads name/value pairs and groups them in a hash table object.
IgnoreSectionHandler The System.Configuration classes ignore the sections marked with this handler because their contents will be processed by other components. This handler is an alternative to using and declaring custom handlers.
NameValueFileSectionHandler Reads name/value pairs from a file referenced in the <appSettings> section and groups them in a NameValueCollection object.
NameValueSectionHandler Reads name/value pairs and groups them in a NameValueCollection object.
SingleTagSectionHandler Reads settings from attributes stored in a single XML node. The data is returned as a hash table.

In the .NET Framework, the classes in the System.Configuration namespace are responsible for parsing the contents of the configuration files. These classes are designed to process the entire contents of the configuration files. The classes also throw an exception when a configuration section lacks a corresponding entry in the <configSections> block and when the layout of the data does not match the declaration.

Of the five section handlers, we have examined NameValueSectionHandler and NameValueFileSectionHandler. The DictionarySectionHandler class is very similar; it differs only in that it stores settings in a hash table instead of in a NameValueCollection object. Collection objects are more efficient if they are used to store a small number of items (ideally fewer than 10), whereas a hash table provides better performance with large collections of items. The IgnoreSectionHandler and SingleTagSectionHandler classes deserve a bit more attention, and we’ll look at them next.

The IgnoreSectionHandler Section Handler

A few subsystems in the .NET Framework store configuration data in the machine.config file but process the data themselves, without relying on the services provided by the System.Configuration classes. For example, the machine.config file contains remoting and startup information that is processed outside the configuration engine. To prevent the configuration file from parsing exceptions, you can use a dummy section handler—IgnoreSectionHandler. This handler handles sections of configuration data rather than relying on the classes in System.Configuration. It could be argued that such data should be stored in a system configuration file, like the machine.config file, or in a custom file. Looking at the following excerpt from the machine.config file, you can see that remoting configuration settings are processed by the remoting classes, whereas HTTP run-time configuration settings are processed by a custom handler:

<!-- Tell the .NET Framework to ignore these sections -->
<section name="system.runtime.remoting" 
   type="System.Configuration.IgnoreSectionHandler, System, 
   Version=1.0.3300.0, Culture=neutral, 
   PublicKeyToken=b77a5c561934e089" /> 

<!-- Employ a custom section handler -->
<section name="httpRuntime" 
   type="System.Web.Configuration.HttpRuntimeConfigurationHandler, 
   System.Web, Version=1.0.3300.0, Culture=neutral, 
   PublicKeyToken=b03f5f7f11d50a3a" />

In both cases, configuration settings need a customized and more sophisticated layout than name/value pairs. In the first scenario, the handler is embedded in the remoting subsystem; in the second scenario, the handler conforms to the configuration guidelines but is simply not one of the predefined handlers. As mentioned, because by design the configuration classes read through all the contents of a configuration file and throw exceptions whenever they encounter something wrong, custom settings handled outside the configuration namespace must have a section handler, although one that does nothing—the IgnoreSectionHandler handler.

The SingleTagSectionHandler Section Handler

The SingleTagSectionHandler class supports a simpler schema for storing configuration settings. Unlike NameValueSectionHandler, which supports name/value pairs defined within <add> nodes, the SingleTagSectionHandler class uses a single XML node with as many attributes as needed. Each attribute maps to a setting, and the name of the attribute is also the key to access the value.

In other words, the SingleTagSectionHandler class provides an attribute-based view of the configuration settings, whereas the NameValueSectionHandler class (and DictionarySectionHandler as well) provides an element-based representation. The following code shows the way in which settings are stored by a single tag section handler:

<configuration>
   <configSections>
      <section name="MyCountries"
         type="System.Configuration.SingTagSectionHandler" />
   </configSections>
   <MyCountries country1="USA" 
             country2="Italy"
             country3="Iceland" />
</configuration>

Under the Hood of Section Handlers

As mentioned, a configuration section handler is simply a managed class that implements the IConfigurationSectionHandler interface. The classes that implement the IConfigurationSectionHandler interface define the rules for transforming pieces of XML configuration files into usable objects. The created objects can be of an arbitrary type. The following code shows the interface signature:

public interface IConfigurationSectionHandler 
{
   object Create(object parent, object configContext, 
      XmlNode section);
}

The interface includes a single method, Create, that configuration readers call to obtain an object that represents the contents of a particular setting. This method takes three arguments: a parent object, a context object, and a section XML node. In general, the configuration object can be obtained by combining the information read and composed in a parent directory with the current settings. This information is stored in the parent argument. A configuration setting can’t always have a parent path, however; this is possible only with web.config files, which are specifically designed to support configuration inheritance. For all other configuration files, the parent argument of the Create method is always null. The parent argument being passed should not be altered, and if a modification is necessary, you first clone the object and then modify it.

Note

If it isn’t null, the parent argument is guaranteed to be an object returned by a previous call made to the Create method on the same section handler object. Therefore, by design, the type of the parent argument is identical to the return type of the current implementation of Create. For example, if the Create method returns a NameValueCollection object, the parent argument can only be an object of type NameValueCollection or null.


A section handler object might be used in any configuration file, including a web.config file. For this reason, when implementing the IConfigurationSectionHandler interface, you should check the value in the parent argument and act accordingly. We’ll look at an example of this in the section “Implementing the DataSet Section Handler,” on page 653.

The configContext argument is non-null only if you use the section handler within a web.config file in an ASP.NET application. In this case, the argument evaluates to an object of type HttpConfigurationContext, whose only significant member is a property named VirtualPath. The VirtualPath property contains the virtual path to web.config with respect to the ongoing Web request. In this way, you can determine the level of configuration nesting at which your handler is called to operate.

Finally, the section argument is the XML DOM node object rooted at the section to be handled. The argument is an XML DOM subtree that represents the data to be processed.

Note

To better understand the rather symbolic role played by the IgnoreSectionHandler section handler class, consider what the implementation of its Create method looks like:

object Create(object parent, object context, XmlNode section)
{
   return null;
}

No information is returned, but neither is an exception thrown.


Customizing Attribute Names

Configuration settings are stored using predefined attribute names: key for the setting’s name, and value for the actual contents. Such names are hard-coded as protected members in the NameValueSectionHandler and DictionarySectionHandler classes. Their associated properties are named KeyAttributeName and ValueAttributeName, respectively. To customize those names, you must derive a new class, override the properties, and use the new class as your section handler.

The following code demonstrates a class that inherits from NameValueSectionHandler and simply renames the attributes to be used for the settings. Instead of the default names key and value, SettingKey and SettingValue are used.

public class CustomNameValueSectionHandler : NameValueSectionHandler
{
   public CustomNameValueSectionHandler() : base()
   {
   }

   protected override string KeyAttributeName
   { 
      get{return "SettingKey";}
   }   
   protected override string ValueAttributeName
   { 
      get{return "SettingValue";}
   }   
}

Note that the KeyAttributeName and ValueAttributeName properties are read-only, protected, and virtual. You must retain the same modifier and override the properties in a new class. There is no need to make the properties read/write. The preceding class is defined in the sample application AppSettings_CS available in this book’s sample files and enables you to access the configuration file shown here:

<configuration>
   <configSections>
      <sectionGroup name="AppName">
         <section name="CustomSection" 
            type="AppSettings_CS.CustomNameValueSectionHandler, 
               AppSettings_CS" />
      </sectionGroup>
   </configSections>
   <AppName>
      <CustomSection>
         <add SettingKey="Property" SettingValue="My value" />
      </CustomSection>
   </AppName>
</configuration>

The beauty of these section handlers is that they encapsulate all the logic necessary to access settings in the configuration file. The application is not affected by the actual layout of the setting. As a result, reading the preceding value requires the same high-level code, regardless of the attribute names you use, as shown here:

NameValueCollection coll;
coll = ConfigurationSettings.GetConfig("AppName/CustomSection");
MessageBox.Show(coll["Property"]);

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.38.24