Saturday, August 21, 2010

Custom settings in Web.Config

Ever felt the need to switch settings in your web application based on the server it was running on? Well, I have. Suppose you have a connection string in your Web.Config (encrypted, sure). You don't want to be changing the configuration manually everytime you switch from development, to testing and to production. So here's what I do.
First, you create a new section in the Web.Config file.


The mySettings element is inserted as a child of the configuration root element in your Web.Config.

[mySettings]

[!-- development --]

[Configuration url="http://localhost"]

[add key="ConnectionString" value="server=(local);database=Northwind;user id=sa;password=..." /]

[add key="SettingWhatEver" value="true" /]

[/Configuration]

[!-- testing --]

[Configuration url="http://testserver"]

[add key="ConnectionString" value="server=testserver;database=Northwind;user id=dbusr_test;password=..." /]

[add key="SettingWhatEver" value="true" /]

[/Configuration]

[!-- production --]

[Configuration url="http://liveserver"]

[add key="ConnectionString" value="server=prodserver;database=Northwind;user id=dbusr_prod;password=..." /]

[add key="SettingWhatEver" value="false" /]

[/Configuration]

[/mySettings]

*** note here [=< and ]=>

Then, you create a custom section handler for the Web.Config file.

using System.Collections;


using System.Xml;

using System.Configuration;

public class MySettings : Hashtable, IConfigurationSectionHandler
{
public object Create(object parent, object configContext, System.Xml.XmlNode section)
{

string HostUrl = HttpContext.Current.Request.Url.Host;

XmlNode NodeSetting = null;

XmlNodeList NodeSettings = null;

Hashtable Settings = new Hashtable();

NodeSettings = section.SelectNodes("Configuration[contains(@url,'" + HostUrl + "')]/add");

foreach (XmlNode NodeSetting_loopVariable in NodeSettings) {

NodeSetting = NodeSetting_loopVariable;

this.Add(NodeSetting.Attributes.GetNamedItem("key").Value, NodeSetting.Attributes.GetNamedItem("value").Value);

}
return this;
}
}


This section handler will read from the mySettings element, and select the node with the url-attribute that contains the HostUrl value. This is a simple XPath expression, perhaps you want to finetune it depending on your needs.

Finally, you go back to the Web.Config and make sure the section is understood and read by adding this element to the Web.Config





The first attribute holds the custom section name in the Web.Config. The second attribute holds the class that will handle this section (WebApp.MySettings) and the assembly where this class can be found. The section handler is located right under the configuration root element, but before the mySettings element mentioned above. Be aware that XML is case-sensitive.
Now that your done, you can access the desired setting through:

string constr = ConfigurationManager.GetSection("mySettings")("ConnectionString");

Depending on the host you are running the web application on, this will return the development, testing or production connection string.