Question

Anyone have any good tips on handling differences in web.config settings between environments? I've considered creating a 'config' folder in our source control system but outside of the web hierarchy, and having the deployment process copy the appropriate config files (web.dev.config,web.staging.config, web.production.config) into the web folder upon deployment. I've also seen posts on how to programmatically change the config settings (WCF endpoints, connection strings, etc) when the app starts.

What are considered best practices here, and what experiences has everyone had with these or other approaches?

Update Sep 2010

It's worth noting that Visual Studio 2010 adds this ability via web.config transforms. When you use the build configuration manager (Build|Configuration Manager...) to create different configurations for your project (say, Debug, Dev, Staging and Release), VS adds web.*.config files to the solution. The default web.config contains baseline settings that you'll use for debugging. web.release.config, web.staging.config, etc contain XSLT transforms that will be applied whenever you publish your project based on the active build configuration.

Was it helpful?

Solution

With the new VS you can use web config transformations.

Read more here: http://msdn.microsoft.com/en-us/library/dd465326.aspx

OTHER TIPS

My approach has been to have multiple config files. I put all environment agnostic stuff (i.e. doesn't matter if dev, staging, or production) in the web.config file. Anything that is specific to the environment (i.e. database connection info, logging, debug settings, etc.) I put into a local.config file specific to the environment. You can then include the local.config settings in the web.config using configSource (http://weblogs.asp.net/fmarguerie/archive/2007/04/26/using-configsource-to-split-configuration-files.aspx)

Web.config can then be checked into source control. Don't check in the local.config files - that forces you to deploy the correct one in your deploy scripts.

I use CruiseControl.NET/NAnt and NAnt has an XMLPoke task that allows you to go in as you're building and alter any config setting using XPath queries.

So in each of my build targets (DEV, UAT, STAGING etc) I set a bunch of properties and then call the master build target. The master build target takes the values of all the properties and XMLPokes them into the config and builds.

One method I've seen and used is where you setup keys within your web.config to differentiate the computers by name.

So for instance:

<add key="comp1.Environment"       value="DEV"/>
<add key="compdb1.Environment"     value="PROD"/>
<add key="compstage.Environment"    value="STAGE"/>

Obviously comp1, compdb1 are the actual computer names.

You would then setup something like:

<add key="KeyName,DEV"   value="DevEnvironmentValue"/>

In your code you would need to check what environment the application is running on and then get the appropriate key, so for instance.

private string GetKeyValue() {
    string machineName  = String.Concat(System.Environment.MachineName, ".Environment");
    string environment  = ConfigurationManager.AppSettings[machineName];
    string key          = String.Concat("KeyName", ",", environment);
    string keyValue       = ConfigurationManager.AppSettings[key];

    return keyValue;
}

There's a project type named Web Deployment project, freely available from Microsoft that allow you to do exactly that. You can replace sections of your web.config, depending on your solution configuration (debug, release etc.) We use that for more than a year and it works well. It's available for VS2005 and VS2008.

Hope this will help

While some of the other answers may be more suitable I'll just add that Matt Berseth rolled his own method back in 2007...

In summary he keeps all the values that vary between environments in a proprietary text file and uses a custom tool during the build process to merge the values into the .config files.

In a comment on that post Doron Yaacoby also comments:

"there is a task in MSBuild Community Tasks that can achieve this (and more) for you, which is called XmlMassUpdate. Ive written about it in my blog"

Here's how to add different configs that can be customized for your deployment environments in VS2012

  1. Right mouse click on the solution and select configuration manager
  2. Click the Configuration Manager button
  3. Under the Configuration column select combo box against the project that you want to add a configuration to and Select
  4. Create a new configuration with a name like TEST and copy settings from Release and check the Create new solution configurations checkbox
  5. Right mouse click on the Web.config
  6. Add Config Transform
  7. Then you get an extra web.config Eg web.TEST.config

After this you need to modify web.TEST.config with some transformations specific to your TEST environment

You need to INSTALL for an environment, not BUILD for one. In the real world, you have to install in prod what was tested in QA, no rebuilding allowed. At least in my world that's the case.

 Easy way to have that is having an Enumeration , then having a switch statement based on the server name ( if its stable name ) .  
 Call GetURIPath() where ever you require to fetch details , here I given the examples for url's used 


public class StaticData
{
    public enum enumEnvironment
    {
        envNONE = 0,
        envLOC = 1,
        envDEV = 2,
        envTEST = 3,
        envPROD = 4
    }
     private static enumEnvironment GetCurrentEnv()
    {
        if (ConfigurationManager.GetSection("DBSettingsGroup/DBSettings") == null && ConfigurationManager.GetSection("DBSettings") == null)
        {
            return enumEnvironment.envLOC;
        }
        else
        {
            NameValueCollection NVCollection = new NameValueCollection();
            NVCollection = (NameValueCollection)ConfigurationManager.GetSection("DBSettingsGroup/DBSettings");
            if(NVCollection == null)
            {
                NVCollection = (NameValueCollection)ConfigurationManager.GetSection("DBSettings");
            }

            string sEnv = NVCollection.GetValues("serverrole").ToString();

            switch (sEnv.ToUpper())
            {
                case "DEV-ISOLATED":
                    return enumEnvironment.envDEV;
                case "DEVELOPMENT":
                    return enumEnvironment.envDEV;
                case "TEST":
                    return enumEnvironment.envTEST;
                case "PRODUCTION":
                    return enumEnvironment.envPROD;
                default:
                    return enumEnvironment.envNONE;
            }
        }
    }
   public static string GetURIPath()
    {
        switch (GetCurrentEnv())
        {
            case enumEnvironment.envPROD:
                return "http://produrl/yourapp/api/";
            case enumEnvironment.envTEST:
                return "http://testurl/yourapp/api/";
            case enumEnvironment.envDEV:
                return "http://devurl/yourapp/api/";
            default:
                return "http://localhost/yourapp/api/";
        }
    }

}

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top