Chapter 2: Examining the ASP.NET Configuration Architecture
The first chapter provided a quick overview of ASP.NET Configuration. This chapter takes a closer look at the configuration architecture and how it works. Topics covered in this chapter include:
- The rules of the hierarchical model, and how you can apply settings to a server, an application, a directory, and even a single file.
- How configuration sections are processed and how the values are accessed by applications.
- The internals of a sample configuration section handler.
|
|
Sample Chapter from the book:

Microsoft® ASP.NET Setup and Configuration Pocket Reference
|
Hierarchical Configuration ModelAs discussed in Chapter 1, the ASP.NET configuration model inherits settings from server to application through a hierarchical model. With a hierarchical model, you can specify settings in the machine.config or web.config file of a parent application, and those settings will propagate to any child applications. Child applications can inherit from parent applications, and all applications inherit from the machine.config file. You can specify settings for an entire server, a single or multiple applications, single or multiple directories, or even a single file. The following rules apply to the inheritance of configuration settings.
- Applications first inherit their settings from the machine.config file of the server, then from the web.config file of any parent applications, and finally from their own web.config file.
- The settings in each web.config file override the settings from the machine.config and web.config files before it.
- Inheritance follows the URL of the requested resource and not necessarily the physical structure of the files.
- The settings in the machine.config file or a parent application’s web.config file can prevent settings from being overridden.
- The settings can be targeted to a specific directory, application, or file using the location setting.
To better demonstrate these inheritance rules, let’s take a look at a scenario involving multiple applications and directories. For this example, you will use three applications: App1, App2, and App3. Figure 2-1 is an overview of the virtual structure of these applications.

Figure 2-1 The virtual structure of the sample applications.
In Figure 2-1, App1 and App3 are root applications, and App2 is a sub-application of App1.
The inheritance in the hierarchical model looks first at virtual structure, and then at the physical structure of the applications. Figure 2-2 shows the physical structure of the applications.
Figure 2-2 shows that App1 is a sub-directory of the wwwroot directory, and that App2 and App3 are sub-directories of App1. You will notice that SubDir is also a sub-directory of App1, but it is not an application or virtual directory in IIS.
- Enable tracing in the machine.config file on the server by following the steps in "Editing Configuration Files" in Chapter 1.
By making this change in the machine.config file, tracing will be enabled for all the applications and .aspx files on the server.
- Disable tracing in the web.config file of App1, the first Web application.

Figure 2-2 The physical structure of the sample applications.
You will see the following results on the following URLs when they are accessed. In this example we are using http://www.northwindtraders.com/ as the site name. Replace this with your site name when testing.
- http://www.northwindtraders.com/App1 This URL inherits enabled tracing from the machine.config file, but the setting in the web.config file of App1, which disables tracing, overrides it. Therefore, tracing is disabled for this URL.
- http://www.northwindtraders.com/App1/App2 Because App2 is a sub-application of App1 in the virtual structure, tracing is disabled here also because App2 inherits from the web.config file of App1, and there is no conflicting setting in the web.config file of App2.
- http://www.northwindtraders.com/App1/SubDir All files in the SubDir directory have tracing disabled because they inherit the setting from the web.config file of App2.
- http://www.northwindtraders.com/App3 App3 still has tracing enabled because it inherits only from the machine.config file of the server. Even though it is a physical child of App1, it is not a virtual child of App1.
- http://www.northwindtraders.com/App1/App3 App3 is its own application, but it is still a sub-directory of App1 and can be accessed by that path. As a result, App3 has tracing disabled because it inherits from the web.config file of App1.
The URL of the resource determines which configuration settings the resource will inherit. In other words, identical resources can inherit different configuration settings depending on the URL used to access them. With this understanding of how configuration settings are inherited from server to applications, let’s take a look at how to target configuration settings.
Targeting Configuration SettingsBy using the location tag, you can target settings to a particular path, application, or file. This is particularly useful when you want to use a different setting for a physical directory but don’t want or need to make that directory an application. For example, you might want a single directory to have different trace settings. You can accomplish this by using the location tag and adding the following text to the web.config file of App1.
<location path="SubDir"> <system.web> <trace enabled="false" /> </system.web> </location>
<location path="notracepage.aspx"> <system.web> <trace enabled="false" /> </system.web> </location>
This disables tracing for all the files in the SubDir directory.
Tracing would also be disabled for any sub-directories of the SubDir directory. You can also use this procedure to assign configuration settings to a single file.
This disables tracing for the single file notracepage.aspx in the root directory of App1.
Preventing Configuration Settings from Being OverriddenAs you have seen, you can override settings in the web.config file of an application. However, there are times when you might like to prevent settings from being overridden. Luckily, there is a setting that enables you to do this.
By setting allowOverride to false in either the machine.config or web.config file, no matter what you specify in the inheriting web.config file of the application, in this example, tracing will always be disabled.
<system.web> <trace enabled="false" allowOverride="false" /> </system.web>
<location path="SubDir" allowOverride="false > <system.web> <trace enabled="false" /> </system.web> </location>
You can also use this in conjunction with the location tag.
<location path="SubDir" allowOverride="false > <system.web> <trace enabled="false"> </system.web> </location>
Keep in mind that if you use the allowOverride="false" property, any application that attempts to override this setting will throw a configuration error. Be sure that none of the applications are attempting to set this value before you set it to allowOverride="false" or using this property will break those applications.
Examining Configuration Section HandlersSo far, I have covered where to specify the settings, how the settings inherit, and how you can target and lock settings. Now let’s look at how the configuration settings are used. Configuration section handlers process the settings that are specified in configuration files and make them available to applications. Configuration section handlers are classes that implement the IConfigurationSectionHandler interface. These classes interpret and process the configuration file settings and return a configuration object based on those settings.
Configuration section handlers are first declared in configSections, as discussed in the last chapter. Let’s take a look at the configuration handler declaration again.
<section name="appSettings" type="System.Configuration.NameValueFileSectionHandler, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<appSettings> <add key="MyPassword" value="Secret" /> <add key="ServerIP" value="192.168.31.1" /> </appSettings>
This declaration is for the <appSettings> section of the configuration file. The <appSettings> section is used to store name/value pairs that you want to access from any of the application files. The declaration points the configuration file to the class that will handle this section. Here is a sample <appSettings> section that adds a couple of sample name/value pairs.
<appSettings> <add key="MyPassword" value="Secret"> <add key="ServerIP" value="192.168.31.1"> </appSettings>
These settings can then be accessed from the applications, which makes it very simple to keep track of and change settings that you will need to use on different pages or in different applications. You have seen where the declaration handler is declared, but you cannot look at the actual declaration handler code of the .NET Framework. However, you can look at the Microsoft Shared Source CLI Implementation (codename: Rotor) source code for the same handler, which is the next best thing.
The following is the configuration section handler for the <appSettings> section, which is called NameValueFileSectionHandler. I have removed code unrelated to this discussion.
//------------------------------------------------------------------ // <copyright file="NameValueFileSectionHandler.cs" company="Microsoft"> // // Copyright (c) 2002 Microsoft Corporation. All rights reserved. // The use and distribution terms for this software are contained in the // file named license.txt, which can be found in the root of this // distribution. By using this software in any fashion, you are agreeing // to be bound by the terms of this license. // You must not remove this notice, or any other, from this software. // // </copyright> //------------------------------------------------------------------
#if !LIB namespace System.Configuration { using System.IO; using System.Xml; public class NameValueFileSectionHandler : IConfigurationSectionHandler { public object Create(object parent, object configContext, XmlNode section) { object result = parent; // parse XML XmlNode fileAttribute = section.Attributes.RemoveNamedItem("file"); result = NameValueSectionHandler.CreateStatic(result, section); if (fileAttribute != null && fileAttribute.Value.Length != 0) { /*Removed for Brevity, this section would handle if there was a file="" property in the appSettings section */ } return result; } } } #endif
This handler checks if a file="" property is present, and then returns a value based on the NameValueSectionHandler.CreateStatic method if that property is blank. This is the method that will create the configuration object. This is the code for the NameValueSectionHandler.
//------------------------------------------------------------------ // <copyright file="NameValueSectionHandler.cs" company="Microsoft"> // // Copyright (c) 2002 Microsoft Corporation. All rights reserved. // The use and distribution terms for this software are contained in the // file named license.txt, which can be found in the root of this // distribution. By using this software in any fashion, you are agreeing // to be bound by the terms of this license. // You must not remove this notice, or any other, from this software. // // </copyright> //------------------------------------------------------------------ #if !LIB namespace System.Configuration { using System.Collections; using System.Collections.Specialized; using System.Xml; using System.Globalization; public class NameValueSectionHandler : IConfigurationSectionHandler { const string defaultKeyAttribute = "key"; const string defaultValueAttribute = "value"; public object Create(object parent, object context, XmlNode section) { return CreateStatic(parent, section, KeyAttributeName, ValueAttributeName); } internal static object CreateStatic(object parent, XmlNode section) { return CreateStatic(parent, section, defaultKeyAttribute, defaultValueAttribute); } internal static object CreateStatic(object parent, XmlNode section, string keyAttriuteName, string valueAttributeName) { ReadOnlyNameValueCollection result; // start result off as a shallow clone of the parent if (parent == null) result = new ReadOnlyNameValueCollection(new CaseInsensitiveHashCodeProvider( CultureInfo.InvariantCulture), new CaseInsensitiveComparer( CultureInfo.InvariantCulture)); else { ReadOnlyNameValueCollection parentCollection = (ReadOnlyNameValueCollection)parent; result = new ReadOnlyNameValueCollection(parentCollection); } // process XML HandlerBase.CheckForUnrecognizedAttributes(section); foreach (XmlNode child in section.ChildNodes) { // skip whitespace and comments if (HandlerBase.IsIgnorableAlsoCheckForNonElement( child)) continue; // handle <set>, <remove>, <clear> tags if (child.Name == "add") { String key = HandlerBase.RemoveRequiredAttribute( child, keyAttriuteName); String value = HandlerBase.RemoveRequiredAttribute( child, valueAttributeName, true /*allowEmptyString*/); HandlerBase.CheckForUnrecognizedAttributes(child); result[key] = value; } else if (child.Name == "remove") { String key = HandlerBase.RemoveRequiredAttribute( child, keyAttriuteName); HandlerBase.CheckForUnrecognizedAttributes(child); result.Remove(key); } else if (child.Name.Equals("clear")) { HandlerBase.CheckForUnrecognizedAttributes(child); result.Clear(); } else { HandlerBase.ThrowUnrecognizedElement(child); } } result.SetReadOnly(); return result; } protected virtual string KeyAttributeName { get { return defaultKeyAttribute;} } protected virtual string ValueAttributeName { get { return defaultValueAttribute;} } } } #endif
This code creates a configuration collection object that contains the different key and value pairs from the <appSettings> configuration section. I won’t spend a large amount of time focusing on this handler’s exact code, but let’s take a look at a couple of the more important parts. The CreateStatic method is called from the first section handler, and it will create the configuration object. This method creates a ReadOnlyNameValueCollection object that will hold all the different key and value pairs of information.
Let’s take a look at the code that is used to parse the XML.
if (child.Name == "add") { String key = HandlerBase.RemoveRequiredAttribute(child, keyAttriuteName); String value = HandlerBase.RemoveRequiredAttribute(child, valueAttributeName, true/*allowEmptyString*/); HandlerBase.CheckForUnrecognizedAttributes(child); result[key] = value; }
If the XML child name is equal to "add," this code adds the key/value pair to the ReadOnlyNameValueCollection object called result. When you reference the <appSettings> collection in the code, you access this collection to reference the values you are storing in this section.
Configuration section handlers interpret and make available all the settings in a particular section. Chapter 9 will cover how to create custom configuration section handlers to interpret the settings for the custom sections.
Key Points
- The hierarchical configuration model inherits from server to application and from application to application in a variety of ways. This inheritance is based on the URL that is used to access the resource in question.
- You can use the location tag to target configuration settings to a particular directory or even a single file.
- You can use the allowOverride setting to prevent a setting from being overridden by a later web.config file.
- Configuration section handlers make the settings in the configuration available to applications by processing the XML and returning a configuration object.
|