Managing complex Web.Config files between deployment environments

.Netasp.netVisual StudioWcf

.Net Problem Overview


Does anyone know of any good tools/utilities for managing Web.Config files between different build/deployment environments?

For example, I have a WCF project that in development I don't want to enable SSL, but I do want it enabled in production. I want different logging settings, different DB connection strings, different error handling, different file paths... Even some different Unity framework bindings (wire up mocks for unit testing instead of the real objects for deployment).

Maintaining individual copies of the Web.Config is a pain, because adding a new web service means editing multiple files and keeping them in sync.

I've also noticed that if you muck with the Web.Config too much by hand, Visual Studio will choke if you try to use the "add item" wizard to, say, add a new Web Service for WCF, since it has to modify the Web.Config to add the endpoint,a nd can't parse it any more. So I have to be careful not to invalidate the existing Web.Config.

I also thought about just using some regex to do replacements and just building a new Web.Config in a pre-build command. That seems like the best option so far...

Any other ideas? It seems like this should be a very common issue, since the Web.Config should probably never be the same between development and production deployments.


Update:

I decided to write a quick console app that will take all the xml files in a given directory and merge them into one, and only include certain files based on the name.

So I can make in a directory:

WebConfig_All

<configuration>
  <configSections>
    ...
  </configSections>
  <system.web>
    ...
  </system.web>
</configuration>

connectionStrings_Debug

<configuration>
  <connectionStrings>
    <add name="connstr" connectionString="...dev..." />
  </connectionStrings>
</configuration>

connectionStrings_Release

<configuration>
  <connectionStrings>
    <add name="connstr" connectionString="...prod..." />
  </connectionStrings>
</configuration>

Then run my command line tool, and pass in the configuration (Debug, Release, custom...) And it will merge all the files that end in _All" or _<configuration>`.

So now I have 80% of my Web.Config in a single WebConfig_All file, and the 20% custom stuff in separate files per build configuration. I can then run my command line tool as a pre-build task in VisualStudio, or from NAnt, or wherever I want...

I also made my XML merge logic good enough to handle stuff like:

<x>
  <y a="1">
    <z a="1"/>
  </y>
</x>

merge with

<x>
  <y a="1">
    <z a="2"/>
  </y>
  <y a="2"/>
</x>

results in:

<x>
  <y a="1">
    <z a="1"/>
    <z a="2"/>
  </y>
  <y a="2"/>
</x>

Looking good so far... :)


Followup:

This topic is a little old now, so I wanted to point out that VisualStudio 2010 has a feature to do web.config transformations built-in: http://msdn.microsoft.com/en-us/vstudio/Video/ff801895

Of course in typical Microsoft fashion of only implementing any feature 50% of the way, it only works for web projects using web deploy. There is a plugin to enable transformations in other projects, located here: http://www.hanselman.com/blog/SlowCheetahWebconfigTransformationSyntaxNowGeneralizedForAnyXMLConfigurationFile.aspx

You could also use a tool like BuildMaster to manage config files (along with builds, tests, DB scripts, etc...)

.Net Solutions


Solution 1 - .Net

We split out all region specific settings into thier own config file. Under the root of the web app we create a config folder and place the region specific settings there. So whatever files are living under the root of config will get picked up.

our web.config looks something like:

.
.
.
<appSettings configSource="config\appSettings.config"/>
<nlog configSource="config\nlog.config"/>
<applicationSettings>
	<MyApp.UI.Properties.Settings configSource="config\Settings.APGUI.config"/>
	<MyApp.BusinessServices.Properties.Settings configSource="config\Settings.Business.config"/>
	<MyApp.Auditing.Properties.Settings configSource="config\Settings.Auditing.config"/>
</applicationSettings>
.
.
.

So if we are deploying to the release region the build tool will just have an action to replace the files in the root of config with the files from the appropriate region folder. The file structure looks something like:

ADDED: This is how the source control structure looks, the deployed app would just have the config dir with no sub folders or course

\Root
   web.config    
   \Config    
       appsettings.config    
       services.config    
       logging.config    
       \release    
          appsettings.config    
          services.config    
          logging.config    
       \debug
          appsettings.config    
          services.config    
          logging.config

It is pretty clean and supported by any automated build tool(copying/replacing files). The nice side effect is that developers can create different flavors and keep them under source control without affecting the "real" configs.

Solution 2 - .Net

You could use Build Events to manage your web configs. Hanselman has a good article about it.

Basically you have all your different web.configs in the solution you then create (some) new build types. Depending on the build type you run a web.config is copied over the referenced one!

Solution 3 - .Net

You want the XmlMassUpdate task in MSBuildCommunityTasks (does what you're trying to do with your xml console app)

http://msbuildtasks.tigris.org/

use it like this

  <XmlMassUpdate Condition=" '@(ConfigTemplateFile)'!='' And '@(ConfigSubstitutionsFile)'!=''"
    ContentFile="@(ConfigTemplateFile)"
    SubstitutionsFile="@(ConfigSubstitutionsFile)"
    MergedFile="@(ConfigFile)"
    ContentRoot="/configuration"
    SubstitutionsRoot="/configuration/substitutions/$(Configuration)"/>

Solution 4 - .Net

I use the method explained by Scott Hanselman (he explains it much better than I can reproduce this so follow the link :) ) It has worked fine for me...

Solution 5 - .Net

I use this tool: xmlpreprocess

we maintain separate 'property' files for each environment that are merged in by the deployment script.

Solution 6 - .Net

I like to use a build task to automate changing the config file for the desired environment.

Solution 7 - .Net

We use tags in our config files, that are replaced at build time to reflect the intended deployment environment. I've been inspired by Lavablast blog

It's nice to have only one template config file to manage.

The drawback is that you can't easily have custom "sections".

Solution 8 - .Net

Old question, but since it's having a high rank in Google search, I thought it's a good idea to add the web.config transformation syntax, that has been available since VS2010. With this tool, you can have different web.config files for different builds (Debug/Release)

Here is a short summary on how to have two connections strings - one for development (Debug mode) and one for production (Release mode):

1- Set your development connection string in the web.config file. Should look similar to this:

 <connectionStrings>
    <add name="myConnectionString"  connectionString="Data Source=TestDBServer; (etc...)" />
  </connectionStrings>

2- Expand your web.config file and open web.release.config

web.config

3- Use the Replace function to replace the connection string with the one for you want for production. You can use xdt:Locator="Match(name)" attribute to match it with the name of the connection string (myConnectionString) in this example:

<connectionStrings>
    <add name="myConnectionString"  xdt:Transform="Replace" xdt:Locator="Match(name)" 
         connectionString="Data Source=ProdDBServer; (etc...)" />
  </connectionStrings>

4- Preview the transform of the web.config file that will be used during release build by right clicking on the web.release.config file and choosing Preview Transform.

enter image description here

Solution 9 - .Net

I have traditionally used the multiple web.configs as you mentioned. It can be a pain but it is mitigated by file compare tools such as BeyoneComapare2 or KDIff...

Solution 10 - .Net

Annoyance:

I mentioned my little cmd line app to merge XML docs in my 1st update... Well to do that I just use XmlDocument, and eventually just .Save() it to an FileStream.

Unfortuantely, the nodes aren't really in any particular order, and apparently, .NET requires the <configSections> element be the 1st child of the document.

I thought all these fancy tools were supposed to make programming life easier?

Solution 11 - .Net

My favourite two ways of dealing with this are:

A. Keep the settings on the target machine* - In Azure for example you can setup application settings and connection strings that will override the values in web.config. (* - or target machine definition if your infrastructure configuration is dynamic).

B. Make the build/deployment tool (TeamCity, Octopus Deploy, etc, VS Team Services) inject the environment specific values as part of the build and/or deployment. Modern tools support encryption of sensitive settings.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCodingWithSpikeView Question on Stackoverflow
Solution 1 - .NetDanView Answer on Stackoverflow
Solution 2 - .NetcgreenoView Answer on Stackoverflow
Solution 3 - .NetJeremyWeirView Answer on Stackoverflow
Solution 4 - .NetCohenView Answer on Stackoverflow
Solution 5 - .NetGraham AmbroseView Answer on Stackoverflow
Solution 6 - .NetPedroView Answer on Stackoverflow
Solution 7 - .NetmathieuView Answer on Stackoverflow
Solution 8 - .NetS.DavView Answer on Stackoverflow
Solution 9 - .NetJeff MartinView Answer on Stackoverflow
Solution 10 - .NetCodingWithSpikeView Answer on Stackoverflow
Solution 11 - .NettymtamView Answer on Stackoverflow