ASP.NET configuration management: an alternative to web.config

An alternative and flexible way to manage config settings for multiple web applications.

Introduction

ASP.NET web applications that follow the classic configuration settings management technique used nowadays store configuration values in the web.config file. This is an XML configuration file, containing various settings: some of them are targeted to the ASP.NET engine itself (for example: globalization settings, authentication settings, compilation settings); other settings are targeted to the application, and are known as "AppSettings" (from the name of the XML node containing them inside the web.config file). The adoption of a configuration settings management strategy based on web.config is suitable for single web applications, but it quickly becomes unmanageable if you need to maintain the configuration settings for a family of similar web applications, especially when you need to keep aligned some common settings on more and more web.config files. Of course, if the same machine hosts multiple web sites with similar application settings, you always have the chance to store the common settings in the machine.config file, that acts as a "master" configuration file for all the web applications hosted on that machine. But also this approach quickly becomes unusable if your deployment scenario is built on a web farm, with multiple web servers.

I worked for a single project that had lots of web applications, targeted to multiple languages, hosted on multiple, load-balanced web servers, on multiple environments. The number of web applications (and of corresponding web.config files) to be managed was about 105, so I decided to think of a different way to manage those thousands of settings.

This article describes the configuration management solution (alternative to the classic web.config file usage) I adopted. It addresses only the storage of the AppSettings: all the other configurations, targeted to the web engine (like: globalization, compilation, authentication), are still stored in web.config.

Configuration settings storage

I decided to store all the settings on a Microsoft SQL Server 2000 database table, named WebSettings, in a database of your choice, that from now on I'll call CMS (Configuration Management System). The WebSettings table structure contains three main fields:

WebSite, a string indicating the web site that is reading a particular configuration setting (a.k.a.: web site identifier).

KeyName, a string containing the name of the configuration setting (something similar to the value of the original key attribute in an add node of the web.config's appSettings).

KeyValue, a string containing the value of the configuration setting (something similar to the value of the original value attribute in an add node of the web.config's appSettings)

An optional KeyDescr field can contain a description of the configuration key, specifying the allowed values or some setting guidelines. A primary key on the WebSite and KeyName fields will guarantee the uniqueness of each setting.

Each KeyName/KeyValue pair in the WebSettings table must be associated with a particular WebSite. When a particular web site needs a configuration value, a call is given to the function GetWebSetting() - see the code below - and the correct KeyValue is retrieved based on the KeyName supplied and on the requesting web application identity. The GetWebSetting() function definitely implements a functionality similar to the .NET Framework collection ConfigurationSettings.AppSettings() in the System.Configuration namespace. The difference between the two is that GetWebsetting() always returns a String value (eventually an empty string if the desired configuration setting value is not found in the WebSettings table), and never the Nothing value.

The GetWebSetting() function determines the requesting web application identity by inspecting the value of the WebSiteIdentifier key in the web.config associated to the current HTTP context. The WebSiteIdentifier is one of the only two AppSettings keys needed in the web.config file of the calling web application: it permits the identification of the web site itself when querying the WebSettings table. The second AppSettings key is named WebSettingsConnString and contains the connection string needed to connect to the CMS database hosting the WebSettings table:

Hierarchical configuration

The WebSiteIdentifier key is a dot-separated string, containing more substrings identifying classes (or sets) of similar applications. In my specific context, the WebSiteIdentifier was composed of three parts: WebSiteType.Area.Language. When a configuration KeyName/KeyValue pair has to be set for a specific web site, the corresponding WebSite field in the WebSettings table will be filled with the exact three-part web site identifier of the related web application. For configuration KeyName/KeyValue pairs that are common to multiple, similar web applications, you can enter a single entry in the WebSettings table, indicating that it is applicable to a set of web applications; to do so, you will use the special word _DefaultSettings (be sure to start this word with an "underscore" character) as a part of the three-part-dotted identifier. For example:

A WebSettings.WebSite field filled with...

will indicate a KeyName/KeyValue pair...

MySite.Europe.English

only applicable to the single, specific English European "MySite" web site

MySite.Europe._DefaultSettings

applicable to all European "MySite" web sites (any language)

MySite._DefaultSettings

applicable to all "MySite" web sites (any language, any area)

_DefaultSettings

applicable to all web sites ("MySite" and others)

The presence of a _DefaultSettings setting doesn't exclude the possibility to have some specializations for a particular site. In fact, the GetWebSetting() function always looks for a KeyName/KeyValue pair starting from the most specific WebSiteIdentifier it finds in the WebSettings.WebSite field. So, for example, the search matching order for my specific hierarchy was as follows:

WebSiteType.Area.Language

WebSiteType.Area._DefaultSettings

WebSiteType._DefaultSettings

_DefaultSettings

Caching

When the GetWebSetting function is called for the first time, it reads from the CMS database (pointed by the WebSettingsConnStringAppSettings key) the settings related to the requesting application. These values are then cached in the ASP.NET Cache object, in order to minimize the database access during subsequent calls to the GetWebSetting() function. These values remain in the web server cache until one of the following events occurs:

The Application Domain related to the web application is restarted (this happens, for example, if: the web.config file of the application is modified; the bin directory of the application is modified; the Application Pool hosting the application is recycled)

The ASP.NET engine flushes the cache to gain some memory for other tasks

Every time the GetWebSetting() function is called, it checks for configuration values in the cache, if they are present, they are used as they are; otherwise, they are re-read from the database.

If the GetWebSetting() function is called specifying True as a second (optional) parameter, the configuration value is anyway read from the database (and also all the other settings for that web application are reloaded).

If you change some values in the WebSettings table, in order to make them take effect, you have to force a cache flushing so that the GetWebSetting() function re-loads values from the database. You don't need to restart the Application Domain or recycle the Application Pool: to force the configuration settings reload, you can just do a call like the following:

GetWebSetting("", True)

You could implement a special administrative ASPX web page, that - when called - flushes the web settings cache simply invoking the GetWebSetting() function with the second parameter set to True. Be sure to call it on all the web servers involved in the change (don't forget that the ASP.NET Cache object lives in the memory of each server in the farm).

Comments and Discussions

I used this tecnique on a big public sport web site: it was actually a family of sites, with about 100 web.config. I cannot post source code of them, anyway I think the usage description is clear enough on the article.
Everything stands in the GetWebSetting() call when retrieving the setting you need inside the context of the web site you are.
AV

Thanks for your reply, can you send me couple of files on how to use that? Do you need to modify web.config file(except add parts of appSettings), how to call GetWebSetting() function? My email is jinboh@yahoo.com

Imagine to have two web sites, named Web1 and Web2.
They will have respectively a web.config containing, in appSettings, the WebSiteIdentifier set to "MyApps.MyWebs.Web1" and "MyApps.MyWebs.Web2".
The GetWebSetting function should be packaged in an assembly DLL you reference in your web app (but also including it in a sample page could be useful to understand how it works).
After you created the WebSettings table on your preferred SQL Server, imagine to put inside it these three rows:

You will obtain respectively:
on Web1: Bonjour,Ciao
on Web2: Hello,Ciao

"Ciao" is returned in both because of the special behavior of "_DefaultSettings" keyword.
Remember that changes on the values stored on SQL Server are reflected only after refreshing the cache as discussed in the article.

Dear vicneanschi,
the proposed WebSettings solution is for sure not targeted to solve localization issues, so let me say that talking about resources localization is totally out-of-scope, here.

As stated in the article, WebSettings are intended to provide a flexible, centralized, database-based, cached repository for configuration settings for families of similar web sites, possibly hosted on a web farm.

The example I posted above is obviously as simple as an HelloWorld sample, based on words and translated words, just to explain a concept.

(Next step pheraps I'd say "sorry" for using a Response.Write in an HelloWorld sample... )

Hi, I have all my web apps hosted at 1and1.com servers, the classes for .net framework are very restringed, they only let me to have one web.config file in the main root folder of my account and then the others web applications need to read from that particular file. The same is the case for the global.asax file. This approuch from this company is not friendly at all because I loose all the functionallity using custom errors, form authentication, particular configuration for each web application al global side and so on. So this article is going to help me try another way to manage the web applications I have. Changing to another hosting company is not cost effective righ now if someone ask.