Configuration Sections

Create Custom Sections in the web.config File

CoreCoder

LANGUAGES: C# | VB.NET

ASP.NET VERSIONS: 2.0

 

Configuration Sections

Create Custom Sections in the web.config File

 

By Dino Esposito

 

Ever since version 1.x, the .NET Framework has provided a unique XML schema for configuration files that is shared by all types of applications: Windows Forms, ASP.NET, and Web services. In the .NET Framework 1.x, you find made-to-measure classes to read configuration settings, but no writing facilities are provided you must be familiar with XML writers if you want to directly edit the configuration files. In the newest version (ASP.NET 2.0), the configuration API is dual and provides reading and writing capabilities.

 

All configuration files are rooted in the <configuration> element. ASP.NET settings are grouped under the <system.web> element. Each node has a specified number of child elements that provide a full description of the setting. The configuration storage system has a hierarchical nature and spans a few distinct .config files. In this article, I ll take a look at the configuration files in ASP.NET 2.0, the schema in use, and, most of all, how to create custom sections in the application s web.config file.

 

Hierarchy of Configuration Files

There are two types of configuration files: some global to the Web server and some local to the application. Global configuration files are installed together with ASP.NET and live in the CONFIG directory under the installation path of ASP.NET. Here s the path:

 

%WINDOWS%\Microsoft.NET\Framework\[version]\CONFIG

 

The folder contains at least two files: machine.config and web.config. The former defines the schema of the configuration data and sets some default values. The latter completes the information in machine.config and ensures that all predefined attributes in all possible elements have a default value. The web.config file in the installation path is the Web site s configuration file and is shared by all applications deployed to the Web server machine. The site s web.config file is new to ASP.NET 2.0.

 

As mentioned, configuration files form a top-down hierarchy. The assumption is that what s not defined in the current file is defined in an equivalent configuration file up in the hierarchy. The root of the hierarchy is machine.config. It is followed by the site s web.config file and then by the web.config file defined in the root folder of each deployed application. Finally, each subdirectory of the application can have its own web.config file. Each configuration file is scoped to a subtree of resources (pages, images, controls) and can overwrite settings defined at a higher level.

 

Note that not all settings can be overridden at any other level down the hierarchy. The real number of allowed sections and the overriding rules are defined in the machine.config file. The Webmaster, or anyone with administrative privileges, can edit the contents of the machine.config file, and, optionally, define new sections and lock out existing sections to prevent application-driven changes and modifications.

 

Dynamically-defined Sections

The schema of .NET configuration files is fixed, but can originate a variable number of sections. The root element <configuration> has a mandatory child element named <configSections>. Under this element you find listed all the allowed sections and section groups. A section defines a node that is a direct child of <configuration>. A section is identified with the <section> element. If the child is expected to have children of its own, then you define it using the <sectionGroup> element. In turn, the <sectionGroup> may list both <section> and <sectionGroup> elements. The final combination of sections and groups is specific to each application in the sense that each application can have its own custom sections and groups. In the end, the schema of .NET configuration files is variable within common boundaries. Here s the standard piece of script that defines the schema for ASP.NET applications:

 

<configuration>

 <configSections>

   <section name="appSettings" type="..."

    restartOnExternalChanges="false" />

     :

   <sectionGroup name="system.web" type="...">

     <section name="anonymousIdentification" type="..." />

       :

   </sectiongroup>

 </configSections>

 :

</configuration>

 

Although not recommended, you might modify the standard layout of ASP.NET information in your application. More likely, you might want to extend the standard schema to encompass new sections that reflect the needs of specific services that your application offers. In ASP.NET 2.0, this becomes a requirement as soon as you start considering the implementation of a custom run-time service based on the provider model. Let s take a look at the attributes of the <section> element:

 

<section name="..."

        type="..."

        allowDefinition="MachineToApplication" />

 

The name attribute indicates the name of the section. The type attribute contains the full name of the class being used to parse the contents of the section. This class is known as a configuration handler. It is designed to parse the XML subtree rooted in the corresponding section element and return an object that expresses the contents in a processable format. The type attribute is set to a comma-separated string of the form: class,assembly. The class includes full namespace information; the assembly name doesn t include an extension and contains full information if the assembly is strongly typed. What s the role of the allowDefinition attribute? The attribute specifies where the current section can be overridden. Feasible values are listed in Figure 1. If set to MachineToApplication, the section cannot be overridden in a web.config file located in an application s subdirectory. If the attribute is omitted, by default the section can be overridden at will in any web.config file, no matter the location.

 

Value

Description

Everywhere

The section can be used in any configuration file (default).

MachineOnly

The section can be used only in the machine.config file.

MachineToApplication

The section can be used in the machine.config file and in the application s web.config file. You cannot use the section in web.config files located in subdirectories of the virtual folder.

Figure 1: Values for the allowDefinition attribute.

 

The Configuration Section Handler

The configuration section handler is the class that represents the contents of the section. The internal structure of the class changes radically in ASP.NET 2.0. In ASP.NET 1.x, a configuration section handler is a class that implements the IConfigurationSectionHandler interface. The interface contains just one method, Create, which is expected to take the XML subtree in input, and output an object that contains the parsed information.

 

In ASP.NET 2.0, the configuration section handler is a class that ultimately inherits from the ConfigurationSection class. The section handler class defines public properties and maps them to attributes in the XML element. In addition, these class properties are decorated with a special attribute named ConfigurationProperty. Most predefined handlers are coded in the System.Web.Configuration namespace.

 

Let s see how to write a custom section handler. Imagine you want to add a custom section to your web.config file to specify additional settings for ASP.NET pages. The default schema already provides you with a <pages> section under the <system.web> group where you can indicate attributes for pages, such as the default base class, theme, tracing, and attributes equivalent to most of the attributes of the @Page directive. The new <MyPages> section adds new settings that affect the behavior of ad hoc Page-derived classes that you use in applications. In other words, if you re building a Web application based on a hierarchy of page classes, you can indicate offline attributes through a new section in the web.config file. The section I m going to create is a fairly simple one, but illustrates all the necessary points:

 

<MyPages PageBackColor="#color" />

 

The section counts just one attribute, PageBackColor, which indicates the selected color for the page background. The color is expressed as an HTML string that is, through named colors or RGB triplets prefixed by the # symbol. It is essential to note that assigning a value to the PageBackColor attribute doesn t automatically set the background of the page to the specified color. For this to happen, it is required that some running code reads the value out of the web.config file and finds a way to set it. Figure 2 shows the code of the custom section.

 

using System;

using System.Configuration;

using System.Web.Configuration;

using System.Drawing;

namespace Samples

{

  public class MyPagesSection : ConfigurationSection

  {

     private static readonly ConfigurationProperty propPageBackColor = null;

     static MyPagesSection()

     {

        MyPagesSection.propPageBackColor = new ConfigurationProperty(

           "PageBackColor", typeof(string), "yellow",

            ConfigurationPropertyOptions.Required);

     }

      [ConfigurationProperty("pageBackColor")]

     public string PageBackColor

     {

          get

   {

      return (string) base[MyPagesSection.propPageBackColor];

   }

   set

   {

      base[MyPagesSection.propPageBackColor] = value;

   }

     }

  }

}

 

 

Imports System

Imports System.Configuration

Imports System.Web.Configuration

Imports System.Drawing

Namespace Samples

   Public Class MyPagesSection : Inherits ConfigurationSection

       Private Shared ReadOnly _propPageBackColor As ConfigurationProperty = Nothing

       Shared Sub New()

           MyPagesSection._propPageBackColor = New ConfigurationProperty("PageBackColor", _

            GetType(String), "yellow", ConfigurationPropertyOptions.Required)

       End Sub

       <ConfigurationProperty("PageBackColor")> _

       Public Property PageBackColor() As String

           Get

               Return CType(MyBase.Item(MyPagesSection._propPageBackColor), String)

           End Get

           Set(ByVal value As String)

               MyBase.Item(MyPagesSection._propPageBackColor) = value

           End Set

       End Property

   End Class

End Namespace

Figure 2: The source code of the <MyPages> section class (C# and VB.NET).

 

The class inherits from the base class ConfigurationSection and defines one public property named PageBackColor. The mapping between a property and a section attribute is established through the ConfigurationProperty attribute. The parameter of the attribute constructor indicates the name of the section attribute used to feed the property.

 

The current value is stored in a private static and readonly member of type ConfigurationProperty. The member is initialized in the section class constructor by making a direct call to its class constructor:

 

static MyPagesSection()

{

 MyPagesSection.propPageBackColor = new ConfigurationProperty(

      "PageBackColor", typeof(string), "yellow",

      ConfigurationPropertyOptions.Required);

}

 

 

Shared Sub New()

 MyPagesSection.propPageBackColor = New ConfigurationProperty( _

      "PageBackColor", GetType(String), "yellow", _

      ConfigurationPropertyOptions.Required)

End Sub

 

The first two parameters of the constructor indicate the name and type of the configuration property; the third argument sets the default value, if any. Needless to say, you get a run-time exception if the default value doesn t match the property type. Finally, the fourth argument indicates whether the property is required or specifies other behavioral options. Feasible values that you can combine using the bitwise | operator (Or in Visual Basic.NET) are: DefaultCollection, IsKey, and None.

 

Extending the MyPages section with more attributes is easy. You simply add new public properties, store each in a static, readonly ConfigurationProperty member, and decorate the property with the ConfigurationProperty attribute. You can give the property primitive types, such as date, integer, and string, or declare it to be a collection of child elements.

 

Registering the New Section

You cannot use the myPages section inside an existing and predefined section such as <system.web>. You can only make it appear in a web.config file as a direct child of the root <configuration> node. To define a custom section in a web.config file, you first declare it by adding an entry to the initial section of <configSections>:

 

<configuration>

 <configSections>

    <section name="myPages"

             type="Samples.MyPagesSection, MySections" />

 </configSections>

 :

 <MyPages PagaBackColor="green" />

<configuration>

 

The type property in the <section> tag indicates the class being used to read and write the contents of the section. For the sample MyPages section, the system will use the MyPagesSection class in the MySections assembly. If the assembly is strongly typed and located in the global assembly cache (GAC), you should indicate its full name.

 

Note that you can also wrap the new section in a parent section by defining an optional <sectionGroup> element. The use of the section group is, in most cases, recommended to avoid name conflicts:

 

<configuration>

 <configSections>

   <sectionGroup name="MySections" type="MySectionsGroup">

      <section name="pages"

               type="Samples.MyPagesSection, MySections" />

   </sectionGroup>

 </configSections>

 :

<configuration>

 

When declaring a section group you must indicate a type in charge of parsing the contents of the group. The class that represents the section group has a straightforward internal structure. It counts as many properties as there are child sections. Each property is flagged with the ConfigurationProperty attribute:

 

public class MySectionsGroup : ConfigurationSectionGroup

{

    [ConfigurationProperty("pages")]

   public MyPagesSection pages

   {

      get {

         return (MyPagesSection) base.Sections["pages"];

      }

   }

}

 

 

Public Class MySectionsGroup : Inherits ConfigurationSectionGroup

   <ConfigurationProperty("pages")> _

   Public ReadOnly Property pages As MyPagesSection

      Get

         Return MyBase.Sections("pages")

      End Get

   End Property

End Class

 

In this way, you can use a known section name, say <pages>, in a different context.

 

Using the New Section

A custom section requires a custom piece of code to consume its data. Typically, you define a custom section to address the needs of a particular application or perhaps an HTTP module or handler. These components, external to the ASP.NET runtime, are responsible for reading and consuming the contents of the custom section.

 

Let s briefly examine a possible scenario. Imagine you have a custom page class that exports some additional properties; for example, it allows you to set programmatically the background color. This class assumes the existence of a <myPages> section and attempts to read and use information from there. Figure 3 shows some code.

 

public class MyBasePage : System.Web.UI.Page

{

  protected override void OnLoad(EventArgs e)

  {

    string path = Request.ApplicationPath;

    Configuration config = WebConfigurationManager.OpenWebConfiguration(path);

    MyPagesSection section = (MyPagesSection) config.GetSection("myPages");

    // Find the server <body> tag if any

    HtmlControl body = LookupForBody();

    if (body != null)

       body.Attributes["bgcolor"] = section.PageBackColor;

  }

  :

}

 

 

Public Class MyBasePage : Inherits System.Web.UI.Page

 Protected Overrides Sub OnLoad(ByVal e As EventArgs)

     Dim path As String = Request.ApplicationPath

     Dim config As Configuration = WebConfigurationManager.OpenWebConfiguration(path)

     Dim section As MyPagesSection = CType(config.GetSection("MyPages"), MyPagesSection)

     Dim body As HtmlControl = LookupForBody()

    If Not body Is Nothing Then

        ctl.Attributes("bgcolor") = section.PageBackColor

    End If

 End Sub

 :

End Class

Figure 3: A custom page class using a custom section (C# and VB.NET).

 

Conclusion

The structure of .NET configuration files is relatively extensible. It doesn t mean that you can completely change the schema of a .config file, but you re given quite a bit of liberty to create your own sections and store the information according to a given XML schema. Speaking of the XML schema of custom sections, an important change surfaces that you can t help but notice if you ever wrote a custom section in ASP.NET 1.x. The code discussed thus far assumes that the custom section has a pretty simple structure one node and multiple attributes. Indeed, this is the most common scenario and addressing it, as you saw, is quite simple. What if, instead, you need a section with a completely custom XML tree? How can you parse the contents manually?

 

The section class inherits from ConfigurationSection, which, in turn, inherits from ConfigurationElement. Just this class is responsible for the parsing of the XML source. If you need to ever control the parse process, take a look at this class and override a few of its methods.

 

The source code accompanying this article is available for download.

 

Dino Esposito is a Solid Quality Learning mentor and the author of Programming Microsoft ASP.NET 2.0 (Microsoft Press, 2005). Based in Italy, Dino is a frequent speaker at industry events worldwide. Join the blog at http://weblogs.asp.net/despos.

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish