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
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
KeyDescr field can contain a description of the configuration key, specifying the allowed values or some setting guidelines. A primary key on the
KeyName fields will guarantee the uniqueness of each setting.
CREATE TABLE WebSettings (
WebSite varchar(64) NOT NULL ,
KeyName varchar(64) NOT NULL ,
KeyValue varchar(1024) NOT NULL ,
KeyDescr text NULL )
ALTER TABLE WebSettings WITH NOCHECK ADD
CONSTRAINT PK_WebSettings PRIMARY KEY NONCLUSTERED
( WebSite, 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
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:
"WebSiteIdentifier" value="MySite.Europe.English" />
"WebSettingsConnString" value="server=...;database=cms;uid=...;pwd=..." />
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
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
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...|
|only applicable to the single, specific English European "MySite" web site|
|applicable to all European "MySite" web sites (any language)|
|applicable to all "MySite" web sites (any language, any area)|
|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
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:
GetWebSetting function is called for the first time, it reads from the CMS database (pointed by the
AppSettings 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.
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:
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).
Public Function GetWebSetting(ByVal Key As String, _
Optional ByVal ForceCacheRefresh As Boolean = False) As String
Dim dtWebSettings As DataTable
If ForceCacheRefresh Then
If HttpContext.Current.Cache("WebSettingsCache") Is Nothing Then
Dim connStr As String =
ConfigurationSettings.AppSettings("WebSettingsConnString") & ""
If connStr = "" Then
Throw New Exception("WebSettingsConnString key missing in web.config")
Dim siteIdentifier As String =
ConfigurationSettings.AppSettings("WebSiteIdentifier") & ""
If siteIdentifier = "" Then
Throw New Exception("WebSiteIdentifier key missing in web.config")
Dim cnn As New SqlConnection(connStr)
Dim cmd As SqlCommand = cnn.CreateCommand()
Dim SQLstr As String
Dim WebSitePart As String = siteIdentifier
SQLstr = "SELECT KeyName, KeyValue FROM WebSettings" &_
" WHERE WebSite='" & siteIdentifier & "'"
Do While WebSitePart.IndexOf(".") >= 0
WebSitePart = WebSitePart.Substring(0, WebSitePart.LastIndexOf("."))
SQLstr & = " OR WebSite='" & WebSitePart & "._DefaultSettings'"
SQLstr & = " OR WebSite='_DefaultSettings' ORDER BY WebSite DESC"
cmd.CommandText = SQLstr
Dim da As New SqlDataAdapter(cmd)
dtWebSettings, Nothing, Date.MaxValue, TimeSpan.Zero, _
If Key <> "" Then
Dim drs As DataRow() =
dtWebSettings.Select("KeyName='" & Key & "'")
If drs.Length = 0 Then