Click here to Skip to main content
Click here to Skip to main content

Customising the default AppSettings and ConnectionStrings Expression Builders

, 25 Mar 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
Use of Expression Builders in different landscapes (Dev / QA / Prod).

Introduction

I've been using CodeProject for a number of years, and I've been meaning to try to contribute back. This is the first go, and I hope someone will find it useful, even if it is not the most elegant.

The idea is to enable all configuration data for multiple landscapes (Dev / QA / Prod etc.) to be available in a single web.config file.

Background

When I have developed Web applications in the past, I have always had a difficulty with having different sets of settings for my local machine, the shared development machine, and the shared production machines. They all would need a slightly different configuration, particularly connection strings to different databases. I managed to overcome it in ASP.NET 1.1 with my own set of classes which could determine which group of settings to use.

With ASP.NET 2.0, I ran back into this limitation as I wasn't able to do this any more and still had to use the Expressions used, say, for the SQLDataSource or the ObjectDataSource. Finally, with some time on my hands and having liked an idea from an article posted on the use of Expression Builders, I set out to produce something which might do the job for me. Note that I haven't attempted to see whether this would work in ASP.NET 3.0 or 3.5.

The idea was to replace the default Expression Builders, meaning that my new DLL would plug in within a few minutes and not require any changes other than to the web.config.

Using the code

To use the DLL, add a reference to it and then add the following in the web.config:

<compilation debug="true">
  <expressionBuilders>
    <remove expressionPrefix="AppSettings"/>
    <remove expressionPrefix="ConnectionStrings"/>

    <add expressionPrefix="AppSettings" 
      type="Cottle.IT.ExpressionBuilders.MyAppSettingsExpressionBuilder, 
            Cottle.IT.ExpressionBuilders"/>
    <add expressionPrefix="ConnectionStrings" 
      type="Cottle.IT.ExpressionBuilders.MyConnectionStringsExpressionBuilder, 
            Cottle.IT.ExpressionBuilders"/>
  </expressionBuilders>
</compilation>

The default Expression Builders are removed and replaced with our Expression Builders.

Both Expression Builders need some help to determine which landscape they are running in. To do this, they look at the SERVER_NAME server variable and compare it against a group of AppSettings variables which have been given a specific set of names:

<appSettings>
  <add key="ServerRegion{Prod}" value="localhost"/>
  <add key="ServerRegion{Dev}" value="localhostd"/>

Then, further settings, either appSettings or connectionStrings, are set up in a similar way:

  <add key="{Prod}Setting1" value="Setting 1 on Prod"/>
  <add key="{Prod}Setting2" value="Setting 2 on Prod"/>
  <add key="{Dev}Setting1" value="Setting 1 on Dev"/>
  <add key="{Dev}Setting2" value="Setting 2 on Dev"/>
  <add key="abc" value="Can be any"/>
</appSettings>
<connectionStrings>
  <add name="{Dev}NorthwindConnectionString"
       connectionString="Data Source=DevServer;Initial Catalog=Northwind;
                         Integrated Security=True"
       providerName="System.Data.SqlClient" />
  <add name="{Prod}NorthwindConnectionString"
       connectionString="Data Source=ProdServer;Initial Catalog=Northwind;
                         Integrated Security=True"
       providerName="System.Data.SqlClient" />
</connectionStrings>

Everything else in the website or the web application can remain the same and be used as it would be expected to be.

Implementation

The two classes are created in a similar way - they consist of the code in the standard AppSettings and ConnectionStrings Expression builders modified slightly. I got the code by using Reflector.

Firstly, though, I created a small helper class with a couple of static methods which are used by both of the other two classes. The first method determines whether we are in Dev / QA / Prod etc., by looking at the SERVER_NAME server variable, and then looks through all the AppSettings with keys starting in "ServerRegion". It then returns the braces and the name inside them for the match:

internal static string ServerRegion()
{
  string whichServer = 
    HttpContext.Current.Request.ServerVariables["SERVER_NAME"];
  string whichServerRegion = null;

  // Loop through all the AppSettings, looking for ServerRegion Keys
  // and then find a match against our server
  foreach (string key in ConfigurationManager.AppSettings.AllKeys)
  {
    if (key.StartsWith("ServerRegion", StringComparison.CurrentCultureIgnoreCase))
    {
      if (String.Compare(whichServer, ConfigurationManager.AppSettings[key], true) == 0)
      {
        Regex regex = new Regex("\\{(?<textinsidebrackets />\\w+)\\}");
        Match match = regex.Match(key);
        if (match.Success)
        {
          whichServerRegion = match.Groups["TextInsideBrackets"].Value;
          break;
        }
      }
    }
  }

  if (whichServerRegion == null)
    throw new InvalidOperationException("No Server Region Keys" + 
                                        " matching current server name");

  return "{" + whichServerRegion + "}";
}

The other method makes use of the server region and combines it with the appSetting key to find a setting which can be returned. Thus, it will look for keys set up as Region + Key, or Key + Region and finally Key. The last is available so that we can have a single setting common to all landscapes.

internal static string GetAppSetting(string key)
{
  string region = ServerRegion();
  string str;

  str = ConfigurationManager.AppSettings[region + key];
  if (str == null)
  {
    str = ConfigurationManager.AppSettings[key + region];
    if (str == null)
    {
      str = ConfigurationManager.AppSettings[key];
    }
  }
  return str;
}

Within the AppSetting Expression Builder, we then change the method GetAppSetting to return our helper's GetAppSetting. I left all the remaining methods untouched as I found them in Reflector.

public static object GetAppSetting(string key)
{
  string str = Helper.GetAppSetting(key);
  if (str == null)
  {
    throw new InvalidOperationException("AppSetting_not_found");
  }
  return str;
}

The ConnectionString Expression Builder does something very similar.

Points of interest

Is this the right way to get what I need? Possibly not. I have long since learned that the chances of my finding something which hasn't been done before are pretty small. However, I have been searching on and off for something like this for a long time. So, for the time being, it is the best I have. I would welcome comments, but please don't flame me too hard.

One limitation which I have come across is that of the use of any of the Membership / Role Providers which are declared in web.config. They don't seem to use the Expression Builder's version of the Connection String, preferring to get it directly. I don't make a lot of use of either, preferring to use Windows authentication and Group membership to determine access. However, I have been working on cut down versions of both the Membership and Role Providers, and I will gear them up to use the Expression built Connection Strings instead.

History

  • 25 March 2009: First version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Graham Cottle
Software Developer (Senior)
United Kingdom United Kingdom
I have been developing applications for almost 30 years - started with early versions of Basic on the Sinclair ZX80, moving up via UK101 and Amstrad to PC. Played with Assembly as well. First big application was for a complete test set, which was written using QuickBasic (all I had available to me). Moved on to a bit of C and C++ (never really got to grips with them) and then 11 years ago, got into Visual Basic/SQL Server and HTML. Moved onto .NET and then in the last few years changed across to C# when the job market indicated that it would be better.
Have now developed quite a few ASP.NET Applications, and along the way have played with WPF, Silverlight and am currently working on an MVC based application.
Follow on   Twitter

Comments and Discussions

 
QuestionGood article PinmemberAshutosh Arya31-Mar-09 10:16 
AnswerRe: Good article PinmemberGraham Cottle1-Apr-09 4:47 
GeneralRe: Good article PinmemberAshutosh Arya1-Apr-09 5:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.1411022.1 | Last Updated 25 Mar 2009
Article Copyright 2009 by Graham Cottle
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid