Ref: http://aspnet.4guysfromrolla.com/demos/printPage.aspx?path=/articles/032807-1.aspx
Introduction
Most ASP.NET applications include a number of configuration settings, such as connection strings, mail server settings, system-wide default settings, and so forth. While these settings could be hard-coded in the source code, it's usually a wiser idea to place them in a configuration file, such as Web.config
. The reasoning being that if these values need to be modified, editing a configuration file is a lot easier than updating the code, rebuilding, and re-deploying.
We can define custom configuration sections in Web.config
that conforms to a pre-determined XML schema. For example, our web application might have a couple of scalar configuration settings (quoteOfTheDay
and yourAge
) as well as a collection of settings (favoriteStates
) where each setting in the collection can have its own scalar values (name
and abbreviation
, let's say). This configuration information could be expressed in Web.config
using the following XML markup:
<ScottsSettings
quoteOfTheDay="Hello, World!"
yourAge="28">
<favoriteStates>
<add name="California" abbreviation="CA" />
<add name="Missouri" abbreviation="MO" />
<add name="Illinois" />
</favoriteStates>
</ScottsSettings>
In Creating Custom Configuration Sections in Web.config
we examined a technique for parsing the XML in custom configuration section that works in both ASP.NET 1.x and 2.0 applications. This required writing a bit of code. ASP.NET 2.0 applications, however, can utilize .NET 2.0's new configuration API, which makes creating custom configuration sections much easier. Read on to learn more!
Custom Configuration Section Basics
Custom configuration sections can be created in Web.config
through the <configSections>
element, specifying the name of the configuration section and the class type that is responsible for deserializing the configuration XML into a class instance. As we saw in the Creating Custom Configuration Sections in Web.config
article, ASP.NET 1.x applications typically use two classes:
- A handler class, which implements
System.Configuration.IConfigurationSectionHandler
. This class is responsible for loading the configuration markup fromWeb.config
. - A configuration class whose set of properties represent the information captured in the custom configuration section. Along with providing the properties, this class also is responsible for deserializing the configuration XML passed to it from its corresponding handler class.
ConfigurationProperty
attribute. In short, the .NET 2.0 configuration API automatically deserializes the XML into an instance of the configuration class based on the attributes on the class's properties.
In this article we will focus solely on this new 2.0 technique; for more on the technique that works in both ASP.NET 1.x and ASP.NET 2.0, see Creating Custom Configuration Sections in Web.config
.
Creating the Configuration Class
To use the .NET 2.0 configuration API, all we need to do is create a class that derives from the ConfigurationSection
class. This class represents the root XML element of the custom configuration section in Web.config
. To capture scalar data for the custom configuration section, simply add properties with scalar data types and decorate them using the ConfigurationProperty
attribute.
Imagine that we wanted a configuration section that captured two scalar configuration settings: quoteOfTheDay
and yourAge
. We could create a configuration class with the following two properties:
public class ASPNET2Configuration : ConfigurationSection
{
[ConfigurationProperty("quoteOfTheDay", DefaultValue="It is what it is.", IsRequired=false)]
public string QuoteOfTheDay
{
get
{
return this["quoteOfTheDay"] as string;
}
}
[ConfigurationProperty("yourAge", IsRequired=true)]
public int YourAge
{
get
{
return (int) this["yourAge"];
}
}
}
The key parts are in bold. First, note that the class ASPNET2Configuration
is derived from the ConfigurationSection
class. Next, note the class's two properties: QuoteOfTheDay
and YourAge
, of types string
and int
, respectively. The ConfigurationProperty
attribute decorating each property indicates that these properties are to be specified via the custom configuration XML. The ConfigurationProperty
attribute can accept a number of parameters, including:
Name
- this is the first parameter, which specifies the name of the property as encoded in the custom configuration XML inWeb.config
.DefaultValue
- the default value for the property if it is not specified in the custom configuration XML.IsRequired
- a Boolean value that indicates whether the property must be specified in the custom configuration XML. IfIsRequired
is true, but the property's value isn't specified in the custom configuration section inWeb.config
, then an exception will be thrown when attempting to visit the site.
ConfigurationSection
class using
this["XmlAttributeName"]
, and this is the syntax used in the get accessors to read the configuration information. The configuration information cannot be directly written to (hence the omission of a set accessor).
Adding the Custom Configuration Section in Web.config
Defining the custom configuration section in Web.config
for an application that uses the .NET 2.0 configuration API is no different than when using the ASP.NET 1.x approach examined in Creating Custom Configuration Sections in Web.config
. To use the custom configuration section in Web.config
, we need to first define it in the element like so:
<configuration>
<!-- Define the custom configuration sections... -->
<configSections>
<section name="aspnet2ConfigurationDemo" type="ASPNET2Configuration"/>
</configSections>
<system.web>
...
</system.web>
</configuration>
Note that the type
value is the fully-typed name of the configuration class. Since the handler class appears in my App_Code
folder, the value for the type
attribute is simply the class's name (ASPNET2Configuration
). If this class resided in a separate assembly, the type
value would be: "Namespace.ClassName, AssemblyName".
With the custom configuration section specified in <configSections>
, we can add the custom section to Web.config
. Note that the custom section, like <configSections>
, appears outside of the <system.web>
section:
<configuration>
<!-- Define the custom configuration sections... -->
<configSections>
<section name="aspnet2ConfigurationDemo" type="ASPNET2Configuration"/>
</configSections>
<aspnet2ConfigurationDemo
quoteOfTheDay="Love your enemy like thy neighbor."
yourAge="28" />
<system.web>
...
</system.web>
</configuration>
Since the yourAge
property was marked as IsRequired=true
, if the value is omitted a configuration error is displayed when attempting to visit the site with the message: "Required attribute 'yourAge' not found."
Programmatically Accessing the Configuration Information
To work with the configuration information from an ASP.NET page or one of the classes that make up the application's architecture, we need to use the ConfigurationSettings
class's GetConfig
method, passing in the path to the markup we are interested in ("aspnet2ConfigurationDemo", for this example). This can be accomplished using the following code snippet:
ASPNET2Configuration configInfo = (ASPNET2Configuration) ConfigurationSettings.GetConfig("aspnet2ConfigurationDemo");
// Work with the properties from the ASPNET2Configuration class...
string quote = configInfo.QuoteOfTheDay;
...
What's cool about the GetConfig()
method is that is automatically caches the configuration information. This data remains cached until the application is restarted (such as through restarting the webserver, modifying Web.config
, uploading an assembly to the /bin
folder, and so on).
Rather than having to enter the above code each time we want to work with configuration data, we can add a static
method to the ASPNET2Configuration
that encapsulates this logic.
public static ASPNET2Configuration GetConfig()
{
return ConfigurationSettings.GetConfig("aspnet2ConfigurationDemo") as ASPNET2Configuration;
}
With this method in place, accessing a configuration value is as easy as doing the following:
string quote = ASPNET2Configuration.GetConfig().QuoteOfTheDay;
Capturing Collection-Based Configuration Information
The code we've examined thus far has only allowed for scalar properties defined as attributes in the configuration markup. But what if we want to capture a set of values? Imagine that for our application we want to display information about a number of states (or cities or countries), but want to let the page developer dictate what states, exactly, are available from the application. In short, we want to augment the custom configuration markup to include a collection. To accomplish this using .NET 2.0's configuration API we need to create two new classes: one that models the data that represents each instance of the collection and one that models the collection.
For example, imagine that we wanted to capture the name and abbreviation of a variable number of states via the custom configuration section. We would start by creating a class that derives from the ConfigurationElement
class and captures information for a particular state (namely its name and abbreviation). Just like with the ASPNET2Configuration
, these scalar values are specified via class properties using the ConfigurationProperty
attribute:
public class ASPNET2ConfigurationState : ConfigurationElement
{
[ConfigurationProperty("name", IsRequired=true)]
public string Name
{
get
{
return this["name"] as string;
}
}
[ConfigurationProperty("abbreviation", IsRequired=false)] public string Abbreviation
{
get
{
return this["abbreviation"] as string;
}
}
}
Next we need to create a class that models a collection of ASPNET2ConfigurationState
objects. The .NET 2.0 configuration API includes a ConfigurationElementCollection
base class that we can extend to capture a set of ASPNET2ConfigurationState
objects. When extending the ConfigurationElementCollection
class we need to override the CreateNewElement
and GetElementKey
methods. These CreateNewElement
method is responsible for creating a new instance of the object being held by the collection. Each object in the collection is indexed via a key, so we need to specify what property of the objects in the collection qualifies as the key. The GetElementKey
returns the key value for a particular element in the collection.
public class ASPNET2ConfigurationStateCollection : ConfigurationElementCollection
{
public ASPNET2ConfigurationState this[int index]
{
get
{
return base.BaseGet(index) as ASPNET2ConfigurationState;
}
set
{
if (base.BaseGet(index) != null)
{
base.BaseRemoveAt(index);
}
this.BaseAdd(index, value);
}
}
protected override ConfigurationElement CreateNewElement()
{
return new ASPNET2ConfigurationState();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((ASPNET2ConfigurationState)element).Name;
}
}
Now that the two necessary classes have been created, we can add the collection class (ASPNET2ConfigurationStateCollection
) as a property of the ASPNET2Configuration
class:
public class ASPNET2Configuration : ConfigurationSection
{
... QuoteOfTheDay and YourAge properties and GetConfig() method removed for brevity ...
[ConfigurationProperty("favoriteStates")]
public ASPNET2ConfigurationStateCollection FavoriteStates
{
get
{
return this["favoriteStates"] as ASPNET2ConfigurationStateCollection;
}
}
}
A Simple Demo
The download at the end of this article includes the custom configuration classes examined in this article along with a simple demo illustrating how to read the configuration data from code in an ASP.NET page's code-behind class. The demo includes a Label Web control that displays the various configuration setting values. For example, given the following configuration settings:
<aspnet2ConfigurationDemo
quoteOfTheDay="Love your enemy like thy neighbor."
yourAge="28">
<favoriteStates>
<add name="California" abbreviation="CA"/>
<add name="Missouri" abbreviation="MO"/>
<add name="Illinois" />
</favoriteStates>
</aspnet2ConfigurationDemo>
The demo displays the following output:
Be sure to download the demo and code at the end of this article and give it a try on your computer.
Conclusion
In this article we explored the .NET 2.0 configuration API and how it can be used to specify custom configuration settings in Web.config
. Unlike the approach used in ASP.NET 1.x, the custom configuration API automatically handles the deserialization of configuration markup to our configuration classes.
Happy Programming!
By Scott Mitchell