LANGUAGES: All .NET Languages
ASP.NET VERSIONS: 1.0 | 1.1
Define Custom Configuration Sections: Part III
Learn four steps to build custom configuration sections and handlers.
By Don Kiely
The .NET features that let you use the appSettings section are fine for simple, custom-built applications, but they quickly can become a problem in more complex environments. For example, new portions of an application could have conflicts because you can't have duplicate key names. This can make it difficult to integrate an application with an existing Web site, leading to subtle bugs when a .config file higher up in the hierarchy changes the behavior in sub applications. Besides, you should avoid using appSettings as a random dumping ground. Another problem is that the built-in section handlers support only key/value name pairs. If you need some other structure, you'll need to use a custom section and handler.
You must take several steps to create and use a custom configuration section. First, define the structure of the data in your custom section. Next, decide whether you can use one of .NET's built-in section handler classes to read the section or define your own. This class must implement the IConfigurationSectionHandler interface. Then define the configuration section declaration using either <section> or <sectionGroup>, specifying the class used to read the settings. Finally, read the section's settings in your application.
Define the Structure of Setting Data
All ASP.NET configuration files must be well formed XML files. So whatever structure you choose for the data must be able to be formatted as XML data. This is why most .config settings are strings - it's the easiest data type to use with XML. If you can live with strings in a flat structure, you can define a custom section but use the built-in handlers to access the data.
This kind of flat structure would look something like this for a database application where you did not want to store the entire connection string as a single string but instead as its component parts:
<?xml version="1.0" encoding="UTF-8"?>
<!-- User name/password option -->
This would be useful if you need to assemble the string at run time, customizing it for specific conditions. In this case, you either can specify a SQL Server login or Windows integrated authentication by including data for one or the other.
This kind of data lends itself to the key/value structure, or you could use custom XML as shown previously, although you'd have to fit in the UserId and Password data. In this case, the easiest way would be to use the built-in handlers and methods.
But say, for example, that you need this or a more complex structure, perhaps with optional elements. Say the section needs to handle either SQL Server or Windows integrated authentication. In this case, the <Authentication> element would have either <UserId> and <Password> elements as shown previously, or a single <IntegratedSecurity> element:
<?xml version="1.0" encoding="UTF-8"?>
As the structure of the XML becomes more complex, key/value pairs become infeasible. Or, if the data becomes more complex, such as by needing to save binary data - encoded with a method such as Base64 - or you need to serialize an object so the application receives a fully rehydrated object. In these cases, you need to use a custom class to read the .config section.
Create a Custom Handler
If none of the built-in handlers are appropriate, your only choice is to create a custom handler class. It actually is quite simple to meet the interface requirements of the IConfigurationSectionHandler interface: Implement the Create method with this interface in VB .NET:
Public Class CustomConfigHandler : Implements IConfigurationSectionHandler
Public Function Create( _
ByVal parent As Object, _
ByVal configContext As Object, _
ByVal section As XmlNode) As Object _
Typically, the rest of the Create function creates a custom object - defined, of course, by another class in the same application - and populates it with data using the objects passed to the method. The parent object provides a reference to the settings in a corresponding parent section of the .config file. This isn't used often. The configContext object returns an HttpConfigurationContext object when Create is called from the ASP.NET configuration system. And Section is an XmlNode object with the complete set of data within this section. Use the Section object to extract whatever information you need to build the custom object with the section's data.
Define the Configuration Section Declaration
Once you decide on a built-in handler or a custom handler, declaring the class so that .NET knows which class to use to read the data is simple. Use either the <section> or <sectionGroup> element in the <configSections> section of the .config file to specify it. The element takes this form:
type="configuration section handler class, assembly"
If you were to use the NameValueSectionHandler to read the DBSettings section, the <section> element would look like this:
The name attribute defines the name of the section, essentially defining a new XML element in the .config file. The type attribute is the name of the class that will read data from the section. If the assembly has a strong name (which it will if it is in the .NET GAC), you'll need to specify the assembly name and the class's full name, including the version, culture, and public key token.
The optional allow attributes apply only to ASP.NET applications and are ignored for others. allowDefinition specifies where you can use this section, either in any .config file, in machine.config only, or in either machine.config or web.config. allowLocation specifies whether the section can be used within the <Location> element, which lets you apply the settings only to a specific resource at that location. Most applications won't have to worry about either attribute.
Read the Section Settings From Code
Whether you're using one of the built-in section handlers or a custom handler, accessing the data in the .config file is the same: Use the GetConfig method of the ConfigurationSettings class. The one thing to remember is this method returns an Object object, no matter which handler you use for the section. So you need to cast the object to the appropriate type. For example, if you use the NameValueSectionHandler that returns a NameValueCollection, you'll have to cast to that type.
Here's the operation in VB .NET:
Dim nvc As NameValueCollection
nvc = CType(ConfigurationSettings.GetConfig("DBSettings"), NameValueCollection)
And here it is in C#:
nvc = (NameValueCollection)ConfigurationSettings.GetConfig("DBSettings");
Custom section handlers provide an easily implemented, flexible way to use application configuration information.
The sample code in this article is available for download.
Don Kiely is senior technology consultant for Information Insights, a business and technology consultancy in Fairbanks, Alaska. E-mail him at mailto:[email protected].