Wednesday, September 21, 2005

How to handle server-specific configuration settings in C#.Net

One of the biggest hassles I've ever had with deployment so far has been trying to ensure that I preserve the correct global variables for my application when I deploy my code from development to staging to production. The primary example being connection strings to the database.

In doing some research, I discovered that .Net allows you to create customized sections in your web.config, and then I came across this article on ToDotNet -http://todotnet.com/archive/2005/06/03/478.aspx.

The article explained how to create a custom XML handler and have it look at the URL to pick the correct connection strings.

Although it was written in VB.Net, it was very easy to port into C#, and I also added two small enhancements:

  • I added the ability to add a default section, just in case the server name doesn't match one of the other defined sections.
  • I also had it include the name of the selected configuration, so that you can export it for debugging purposes - i.e. in case you are not sure which configuration is selected.


Below is my C# code. If you want to implement the full solution, look at the above article:


using System;
using System.Web;
using System.Xml;
using System.Configuration;
using System.Collections;

namespace ujci_v3
{
///
/// Summary description for ConfigHandler.
///

public class ConfigHandler:Hashtable,IConfigurationSectionHandler
{
///
/// For now, an empty constructor
///

public ConfigHandler()
{

}
///
/// This implements the Create interface of IConfigurationSectionHandler,
/// needed to be able to retreive the config info
/// from web.config
///

///
///
///
///
public object Create(object parent,object configContext,XmlNode section)
{
try
{
//Get the host name
string server=HttpContext.Current.Request.Url.Host;
XmlNodeList NodeSettings;

//Find the configuration for this hostname
NodeSettings=section.SelectNodes("configuration[contains(@url,'"+server+"')]/add");

//If no config is found, use the default.
//Also, add the 'Config' key to tell us which configuration is being used.
if(NodeSettings.Count==0)
{
NodeSettings=section.SelectNodes("configuration[contains(@url,'default')]/add");
this.Add("Config","default");
}
else
{
this.Add("Config",server);
}
foreach(XmlNode n in NodeSettings)
{
this.Add(n.Attributes.GetNamedItem("key").Value,n.Attributes.GetNamedItem("value").Value);
}
}
catch(Exception ex)
{
//If any error ocurrs, add the error message as part of the config, to help us debug.
this.Add("Error",ex.Message);
}
return this;
}
}
}