Click here to Skip to main content
15,881,248 members
Articles / Web Development / ASP.NET

Architectural Best Practices - Configurations on Different Environments

Rate me:
Please Sign up or sign in to vote.
2.63/5 (5 votes)
26 Jun 2007CPOL3 min read 36.9K   97   34   8
Most systems developed would have different environments, to name a few, Development, Quality Assurance, or Testing and Live or Production. This article describes how to incorporate all three environment configurations without having to change them while deploying.

Introduction

Most systems developed would have different environments; to name a few, Development (Dev), Quality Assurance (QA), or Testing and Live or Production. This article describes how to incorporate all three environment configurations without having to change them while deploying.

Background

Many of us have developed applications using Connection String settings in a configuration file, either web.config or app.config. This, in turn, has to be deployed in the different environments listed above. For the application to work in a particular environment, we then have to make changes to this setting. This process has to be repeated for each and every release. The luxury of keeping the config files constant does not arise as more and more settings keep adding to the configuration every iteration or the other. If this has to be done over many such settings, we indeed have a problem.

This article addresses this issue, and is primarily meant for architects or technical leads who develop frameworks from which applications are built.

Using the code

This can be readily used in the Business Logic Layer of systems implementing an N-Tier architecture. The AppConfiguration class (attached source) to obtain the configuration value should be part of the core module of the framework. All code to access the configuration should make use of this class. For other systems, a workaround is required. Be prepared to make sacrifices as most of the VS2005 code generators don't anticipate this scenario, but the benefits far outweigh these sacrifices.

This works for both types of configuration files: Web.config or App.config. For the sake of clarity, any reference to configuration file would indicate either of them.

To implement this, we need to add a <switches> node under the <system.diagnostics> node to the configuration file.

XML
<configuration>
    <system.diagnostics>
        <switches>
            <!--
            This is a trace switch. The follow are its values
            0 - Off
            1 - TraceError - Error
            2 - TraceWarning - Error and Warning
            3 - TraceInfo - Error, Warning and Info
            4 - TraceVerbose - Everything
            All the information which are lower than this setting will be activated.
            eg.
            if you set the value 3. The following will be activated
            Error, Warning and Info
            -->
            <add name="Debug" value="0"/>
            <!--
            These are boolean switches.
            0 - Disabled
            1 - Enabled
            Only one among the three should have a value of 1 [preferred]
            rest should be 0.
            -->
            <add name="DevMode" value="1"/>
            <add name="QAMode" value="0"/>
            <add name="LiveMode" value="0"/>
        </switches>
    </system.diagnostics>
</configuration>

Here, four switches are added which are of identical nature. These have been subdivided into two sections: Trace Switch and Boolean Switch. The switches "DevMode", "QAMode", and "LiveMode" each indicate different environments, and as the comment points out, only one environment can be active among them. The distinction of transformation to a specific switch type can be understood in combination with the code declaration.

Here is the code declaration to activate and transform these switches. Please note: the names of switches should match the declaration.

C#
using System.Diagnostics;
//under class declaration
/// <summary>
/// <para>Used to write debug tracing information for the entire application.</para>
/// <para>This is enabled by having a switch declared inside web.config
/// system.diagnostics - switches node</para>
/// </summary>
public static TraceSwitch DebugSwitch = new TraceSwitch("Debug", "Debug mode");

/// <summary>
/// <para>Used to identify settings specific
/// to Development Phase for the entire application.</para>
/// <para>This is enabled by having a switch declared inside web.config
/// system.diagnostics - switches node</para>
/// </summary>
public static BooleanSwitch DevModeSwitch = new BooleanSwitch("DevMode", 
                                            "Identifies Development Mode");

/// <summary>
/// <para>Used to identify settings specific to Quality Assurance
/// or Testing Phase for the entire application.</para>
/// <para>This is enabled by having a switch declared inside web.config
/// system.diagnostics - switches node</para>
/// </summary>
public static BooleanSwitch QAModeSwitch = new BooleanSwitch("QAMode", 
                                           "Identifies Quality Assurance Mode");

/// <summary>
/// <para>Used to identify settings specific to Live Phase for the entire application.</para>
/// <para>This is enabled by having a switch declared inside web.config
/// system.diagnostics - switches node</para>
/// </summary>
public static BooleanSwitch LiveModeSwitch = new BooleanSwitch("LiveMode", 
                                                 "Identifies Live Mode");

After having done the initial declarations, the settings entry needs to be made. Only the <appSettings> node can be used. Instead of having a single entry, settings specific to each environment is made. Here, three entries are made for each setting: one each for Dev, QA, and Live. The settings have a suffix "_Dev", "_QA", and none, respectively, for each of these environments.

XML
<configuration>
  <appSettings>
    <!-- Start of Connection String -->
    <!-- live mode value -->
    <add key="ConnectionString" 
      value="server=192.168.100.3;database=Database_Live;uid=liveUser;pwd=livePassword;"/>
    <!-- quality assurance mode -->
    <add key="ConnectionString_QA" 
      value="server=192.168.100.2;database=Database_QA;uid=qaUser;pwd=qaPassword;"/>
    <!-- dev mode value -->
    <add key="ConnectionString_Dev" 
      value="server=192.168.100.1;database=Database_Dev;uid=devUser;pwd=devPassword;"/>
    <!-- End of Connection String -->

    <!-- Start of User Time Out
        Specifies how long a user is logged in
    -->
    <!-- live mode value -->
    <add key="User_TimeOut" value="50"/>
    <!-- quality assurance mode-->
    <add key="User_TimeOut_QA" value="30"/>
    <!-- dev mode value -->
    <add key="User_TimeOut_Dev" value="10"/>
    <!-- End of User Time Out -->

The logic for obtaining which setting to use is done with code in combination with both the switch and appSettings. It's not necessary to have all settings in this format. If the settings do not change for the environments, you can opt not to use the switch and have a single entry.

C#
using System.Configuration;
//under class declaration
/// <summary>
/// <para>Get the AppSettings value present in the web.config file.</para>
/// </summary>
/// <param name="key">The key setting in appSettings node.</param>
/// <returns>String containing the value based on Mode Switch</returns>
public static string GetAppSetting(string key)
{
    try
    {
        string returnValue = String.Empty;

        //get the value
        returnValue = GetAppSetting(key, true);

        return returnValue;
    }
    catch
    {
        throw;
    }
}

/// <summary>
/// <para>Get the AppSettings value present in the web.config file.</para>
/// <para>The useModeSwitch help to obtain values
///     that are common to Dev, QA or LIVE</para>
/// </summary>
/// <param name="key">The key setting in appSettings node.</param>
/// <param name="useModeSwitch">Specifies whether
/// you want to use Live Mode Values</param>
/// <returns>String containing the value based on Mode Switch</returns>
public static string GetAppSetting(string key, bool useModeSwitch)
{
    try
    {
        string returnValue = String.Empty;


        //uses modeswitch only if you set to true
        //Else gives the Live Mode Values
        if (useModeSwitch)
        {
            //This is done so that the developers can work on their local copy of module
            //settings without having to change the original values
            //This requires that you have mirror nodes in the web.config, which points to
            //your local computer settings.
            if (DevModeSwitch.Enabled)
            {
                key += "_Dev";
            }
            else if (QAModeSwitch.Enabled)
            {
                key += "_QA";
            }
        }

        //get the value
        returnValue = ConfigurationManager.AppSettings[key];

        return returnValue;
    }
    catch
    {
        throw;
    }
}

Here are some uses of the Trace Switch. You can use Trace.Warn to write debug information on a Live environment after enabling tracing, or you can use Debug.Write to output messages in a Development environment without having to set breakpoints.

C#
if(DebugSwitch.TraceError)
{
    //writing to Dubug window
    Debug.Write("Error Line \n");

    //writing to the Trace.axd for each page.
    //Written in Red color. Use this as its easier to find.
    Trace.Warn("Error in Trace");

}
if(DebugSwitch.TraceInfo)
{
    //can take any escape sequence for formatting.
    Debug.Write("\tHi give me a detailed info of the things to come");
    Trace.Warn("Info in Trace");
}

Points to note

  • Since the configuration files are for the entire application, try to break module specific settings in a configuration file of its own and write custom configuration files. Add this module configuration file path to the application configuration file as a setting, and read values from it.
  • The Web Services designer adds a single entry to the web.config for dynamic requests. To recreate this scenario, you need to edit the generated proxy class file to incorporate this scenario. Unfortunately, this gets lost when you rebuild the Web Service reference. Maybe in a future version of Visual Studio, for creating a Web Service proxy class, the logic of choosing the URL would be left to the developer.

History

  • 26 June 2007: Initial version.

License

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


Written By
Architect Riversand Technologies Inc
India India
Head of Engineering at Riversand Technologies Inc.

Comments and Discussions

 
GeneralNot bad idea but... Pin
rr_gruchalski3-Jul-07 22:59
rr_gruchalski3-Jul-07 22:59 
GeneralRe: Not bad idea but... Pin
Anton Pious Alfred4-Jul-07 0:12
Anton Pious Alfred4-Jul-07 0:12 
GeneralGood Idea Pin
Henry Liang27-Jun-07 6:03
Henry Liang27-Jun-07 6:03 
GeneralconnectionStrings in .NET 2.0 Pin
Mark Rodrigues26-Jun-07 13:44
Mark Rodrigues26-Jun-07 13:44 
I have tried this approach previously but I ran into issues using it with the new .NET 2.0 web.config settings (as opposed to the the appSettings as you are using here).

When we started to have data providers which use these connectionStrings our headaches just increased.

We ended up having multiple web.config files which we swap-in automatically as part of our automated publish process.
It is a bit of a pain maintaining 3 of them but web.configs don't change too often (in my experience).

Thanks for the article Smile | :)

Mark Rodrigues
Attend Anywhere
http://www.attendanywhere.com
GeneralRe: connectionStrings in .NET 2.0 Pin
Anton Pious Alfred26-Jun-07 19:52
Anton Pious Alfred26-Jun-07 19:52 
GeneralNot bad Pin
Jamie Nordmeyer26-Jun-07 7:46
Jamie Nordmeyer26-Jun-07 7:46 
GeneralRe: Not bad Pin
Anton Pious Alfred26-Jun-07 19:29
Anton Pious Alfred26-Jun-07 19:29 
GeneralRe: Not bad Pin
Jamie Nordmeyer27-Jun-07 2:49
Jamie Nordmeyer27-Jun-07 2:49 

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

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