Single config file - multiple deployment environments (i.e. dev, qa, prod)

A common problem most application developers face at one time or another is managing the deployment of the environment specific configuration elements their application depends on.  Most often these elements include items like connection strings, file paths or other settings the application requires access to during runtime.  I recently tackled this problem and came up with a solution that seems to work pretty well (we have been using it for the past 4 months without any issues) and fits in great with our automated build enviornment. 

Download code (http://mattberseth.com/downloads/managing_environment_config_settings.zip) for this article.

kick it on DotNetKicks.com

My approach was pretty simple.  I wanted the build process to substitute all of the environment specific config settings while it was making the build.  So if I was doing a regular build at my desk, Visual Studio would automatically use the 'dev' environment settings, but when the automated build server did a 'qa' or 'prod' build, the correct settings would be applied here as well. 

1.  First I identified the elements that varied between the environments (like connection strings), and removed the environment specific entry from the config file

So items like this

    <connectionStrings>
        <add name="northwind" connectionString="server=(local);database=northwind;Trusted_Connection=yes;"/>
    </connectionStrings>

became this

    <connectionStrings>
        <add name="northwind" connectionString="$(northwind.connectionstring)"/>
    </connectionStrings>

Now each setting has a key that can be used by the build to look up the replacement value.

2.  Next, I created an environment file to hold all of the defined environments and their corresponding replacement values.  In my project I named this file 'env.ini'.  As you can see in the screen shot below, I have 3 environments defined (dev, qa and prod), and for each environment I have specified what the value of the $(northwind.connectionstring) key is. 

3. Then, I made a few modifications to the csproj file so it would automatically make the required substitutions while it was executing the build.  These changes included added 3 new items: letting the project know about the new env.ini file, adding a post build step that executes the substitution, and adding a new build type (dev, qa or prod) that allows us to easily toggle between build types.  

<PropertyGroup>

<BuildType Condition=" '$(BuildType)' == '' ">dev</BuildType>

</PropertyGroup>

<ItemGroup> <None Include="env.ini"> <DependentUpon>_App.config</DependentUpon> </None> <None Include="_App.config" /> </ItemGroup> <Target Name="BeforeBuild"> <Exec Command="..\..\tools\fandr\fandr.exe env.ini $(BuildType) _App.config App.config" /> <CreateItem Include="App.config"> <Output TaskParameter="Include" ItemName="Content" /> </CreateItem> </Target>

 That's it.  With this setup, I can build the application from VS and get the expected 'dev' configuration values, or run msbuild from the command-line and override the buildtype properties to generate a build for any of the other environments I have defined ..

To produce a Dev Build using msbuild:

C:\Windows\Microsoft.NET\Framework\v2.0.50727\msbuild .\src\ManagingEnvironmentSettings\ManagingEnvironmentSettings.csproj /p:BuildType=dev

and the corresponding config file that is generated looks like this:

<connectionStrings>

<add name="northwind" connectionString="server=(local);database=northwind;Trusted_Connection=yes;"/>

</connectionStrings>

To produce a Qa Build using msbuild:

C:\Windows\Microsoft.NET\Framework\v2.0.50727\msbuild .\src\ManagingEnvironmentSettings\ManagingEnvironmentSettings.csproj /p:BuildType=qa

and the corresponding config file that is generated looks like this:

<connectionStrings>

<add name="northwind" connectionString="server=qa_dbserver;database=northwind;Trusted_Connection=yes;"/>

</connectionStrings>

To produce a Prod Build using msbuild:

C:\Windows\Microsoft.NET\Framework\v2.0.50727\msbuild .\src\ManagingEnvironmentSettings\ManagingEnvironmentSettings.csproj /p:BuildType=prod

and the corresponding config file that is generated looks like this:

<connectionStrings>

<add name="northwind" connectionString="server=prod_dbserver;database=northwind;Trusted_Connection=yes;"/>

</connectionStrings>

A few items should also be noted:

  1. fandr.exe is the tool that I am using to parse the env.ini file and execute the substitution (its included in the download).
  2. I chose the pattern $(xxx) for my configuration keys, you can choose a different pattern as long as it doesn't conflict with the xml rules
  3. I chose dev, qa, and prod as my environments.  You can have as many environments defined as you would like and can name them whatever you want.
  4. I am using this solution for Console Applications, Windows Services and Web Applications and have not encountered any issues.

While this approach requires a little bit of setup, it seems to be working well.


TrackBack

TrackBack URL for this entry:
http://mattberseth.com/blog-mt/mt-tb.fcgi/20

Listed below are links to weblogs that reference Single config file - multiple deployment environments (i.e. dev, qa, prod):

» Deploying config files to multiple environments - dev, stage, prod from DotNetKicks.com
You've been kicked (a good thing) - Trackback from DotNetKicks.com [Read More]

Comments


Posted by: abdelmasseh on July 6, 2007 12:00 AM

thank you for let me testing thise i hope it,s work

Posted by: Mats on January 24, 2008 12:00 AM

Couldnt you get the same functionality by using the Microsoft Web Deployment Project? Ive used it for a while now without any trouble...

Posted by: William Llugsha on March 18, 2008 12:00 AM

It is so interesting

Posted by: Sylvain BLANCHARD on March 22, 2008 12:00 AM

Really good job Matt.
I tested your projet yesterday and just make some changes to generate the other build configuration (qa, prod) without closing Vsual Studio.

To do it :

1) create dev, qa, prod configuration from Configration Manager
2) remove Debug and Release configurations
3) close VS and edit .csproj like this
3.a) line 3 : remove Debug keyword
3.b) line 5 : replace dev by $(Configuration)

Thats all.

Nice,
But 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 once - http://blogs.microsoft.co.il/blogs/dorony/archive/2008/01/18/easy-configuration-deployment-with-msbuild-and-the-xmlmassupdate-task.aspx

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Consulting Services

Yep - I also offer consulting services. And heck, I'll do just about anything. If you enjoy my blog just drop me an email describing the work you need done.

Recent Comments

  • Doron Yaacoby wrote: Nice, But there is a task in MSBuild Community Tasks that can achieve this (and more) for you, which...
  • Sylvain BLANCHARD wrote: Really good job Matt. I tested your projet yesterday and just make some changes to generate the othe...
  • William Llugsha wrote: It is so interesting ...
  • Mats wrote: Couldnt you get the same functionality by using the Microsoft Web Deployment Project? Ive used it fo...
  • abdelmasseh wrote: thank you for let me testing thise i hope it,s work ...