Some ASP.NET 2.0 Configuration Tips

Illustrates some common techniques for managing web.config sections across multiple deployments and modes for ASP.NET 2.0 Web applications.

 It is a common scenario for ASP.NET Web developers to want to have different sets of configuration data depending on whether the project is being developed locally within Visual Studio in Debug mode, being tested in QA in Release mode, or is in Release mode in production. Also, settings may differ from machine to machine if the Application is deployed into a web farm scenario.

 There are several ways to enhance the ability to maintain separate sets of configuration data; the typical environment is one where we have a number of settings in the web.config that will rarely be changed, and some others that we do want to be able to have changes based on what mode and what location the application is being run from.

 The simplest technique, and one that is workable in a majority of scenarios, is to use the "file=" attribute of the appSettings section:

<appSettings file="myCustomAppSettings.config" >
   <add key="one" value="this will be overwritten by the same key in the external file" />

  //(myCustomAppSettings.config file:)

<add key="one" value="this will replace the key in the main web.config with the same name" />
  <add key="two" value="this is from the external file" />
Note that the root element of the external file is "<appSettings>". Any keys in this file with the same key name as one present in the main web.config appSettings section will overwrite the one in web.config. All others are simply added to the collection, which is a NameValueCollection. For example, the following snippet will write out these values to a Page:

NameValueCollection coll= ConfigurationManager.AppSettings;
    Response.Write("<b>appSettings Section:</b><BR/>");
     foreach(string key in coll.AllKeys)
             Response.Write(key +": "+coll[key] +"<br/>");

Any settings in the web.config appSettings section that aren't replaced by the external definitions because of having the same key name will appear first in the collection.

With this arrangement, you can have a separate "myCustomAppSettings.config" file in each deployment, and when the web.config is deployed, this file is left alone. So, each deployment location can have one of these that will always contain different items without fear of copying a debug web.config into a production deployment and destroying required items and values.

Other standard sections can also be read directly from web.config with the use of an external file. For these you would use the configSource attribute:

<connectionStrings configSource="externConnectionStrings.config" />

//(externConnectionStrings.config file:)
 <add name="conn1" connectionString="Note that the localSqlServer shows up because it is defined in web.config (machine.config) and we did not use the clear or remove directives" providerName="SqlClient" />
Note that in this case the root element of the external file must be the name of the standard section that's being imported - in this case, "connectionStrings".
You will see that because we did not use the <clear /> or <remove name="localSqlServer" /> elements, the list that is output will include this connection string as the first  item in the ConnectionStringSettingsCollection that is output. That is because it is predefined in the master web.config file in the .NET Framework directory:

ConnectionStringSettingsCollection cnColl = ConfigurationManager.ConnectionStrings;
    foreach(ConnectionStringSettings set in cnColl)
            Response.Write(set.Name + ": "+set.ConnectionString +"<br/>");

Finally, you can create a custom configuration "appSettings" section of your choice using the System.Configuration.AppSettingsSection class:

In the web.config:

      <section name ="states" type="System.Configuration.AppSettingsSection,System.Configuration, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> 
</configSections> <states file="states.config" > <add key="Arizona" value="AZ" /> </states> <system.web> ...
In the "states.config" external file:

<add key="New York" value ="NY" />
<add key="Massachusetts" value="MA" />
The elements are combined at runtime, with the one(s) in the web.config appearing first in the collection. Here is an example of reading the above section:

string configPath = HttpContext.Current.Request.CurrentExecutionFilePath;
  configPath = configPath.Substring(0, configPath.LastIndexOf('/'));
      if (configPath.Length == 0) configPath = "/";
         Configuration myRootConfig = WebConfigurationManager.OpenWebConfiguration(configPath);
         AppSettingsSection myAppSettings = myRootConfig.GetSection("states") as AppSettingsSection;
         KeyValueConfigurationCollection myColl = myAppSettings.Settings;
         foreach(KeyValueConfigurationElement elem in myColl)
                Response.Write(elem.Key +": "+elem.Value +"<br/>");

Note that with this arrangement, it is possible to have multiple web.config files at various locations on the filesystem. Provided that the correct path is supplied to the configPath variable as above, that is the web.config that will be loaded and processed.  This provides for a lot more "custom" flexibility at the expense of a bit more complicated code.

The WebConfigurationManager class in the System.Web.Configuration namespace is the main programming point that allows for custom manipulation of configuration data. It includes static methods to retrieve application settings and connection strings.  It works much like the ConfigurationManager class but is oriented toward web applications.

The GetSection static method takes an XPath expression to indicate the section you want to get, and allows you to cast the resulting object to a strongly typed reference for built-in section types.  For example, here is how one can read the <identity... section:

IdentitySection section;
 section = WebConfigurationManager.GetSection("system.web/identity") as IdentitySection;
    if (section != null)
       Response.Write("Identity: Impersonate = " + section.Impersonate);
The output page from the sample app should look like this:

appSettings Section:
one: this will replace the key in the main web.config with the same name
two: this is from the external file

connectionStrings Section:
LocalSqlServer: data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true
conn1: Note that the localSqlServer shows up because it is defined in web.config (machine.config) and we did not use the clear or remove directives

Custom appSettings Section (states):
Arizona: AZ
New York: NY
Massachusetts: MA

Identity Section (via GetSection):
Identity: Impersonate = True

Using the classes in the Configuration namespace, developers have all the tools needed to programmatically create, read, edit and save web.config and related configuration files. There is almost never a need to, nor would it be advisable to "roll your own", unless you are creating custom configuration files  -- all you need to do is study and learn to use the existing API.

If you want to see an advanced use of this concept, download the Enterprise Library 3.1 and look at how the custom sections and their respective classes are created and modified for the various parts of the Library.

Finally, if you create external configuration "include" files, it is a good idea to give them the ".config" extension. Files with this extension are never served by IIS under ASP.NET.  And one final tip: an easy way to get the assembly metadata string for the creation of a configSection element is to load the assembly via Reflector. The entire string will appear at the bottom of the main window when the loaded assembly is selected in the tree list, and you can copy it to the clipboard. Let me tell you, if Google is your friend for finding stuff on the web, Reflector is your friend for finding stuff in the .NET Framework.

The downloadable Visual Studio 2005 Web Application Project will illustrate all of the above.
By Peter Bromberg   Popularity  (6548 Views)