[Source: http://geekswithblogs.net/EltonStoneman]

Web.config transformation is a simple and powerful inclusion in .NET 4.0 for generating configuration files for different environments. It’s a templated match-and replace, and you can put together a homegrown alternative with T4 and some scripting, but the integrated experience is better. It’s limited to web.config in Visual Studio, but with a simple MSBuild target you can leverage it for any config file.

The transform is based on your VS.NET solution configurations, so you can start by replacing the standard “Debug” and “Release” builds with custom configurations to suit your environment. Then run “Add config transformations” by right-clicking the web.config file and VS will generate stub files for each type of build:

The original Web.config file is the source file, and the .DEV, .TEST and .PROD versions are the transform files which contain the overrides needed for each environment. So your Web.config may define a database connection:

Normal
0

false
false
false

EN-US
X-NONE
X-NONE

/* Style Definitions */
table.MsoNormalTable
{mso-style-name:”Table Normal”;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:””;
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin-top:0cm;
mso-para-margin-right:0cm;
mso-para-margin-bottom:10.0pt;
mso-para-margin-left:0cm;
mso-pagination:widow-orphan;
font-size:11.0pt;
mso-bidi-font-size:10.0pt;
font-family:”Calibri”,”sans-serif”;
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:”Times New Roman”;
mso-bidi-theme-font:minor-bidi;}

<connectionStrings>

<add name=db1

connectionString=” “

providerName=System.Data.SqlClient />

</connectionStrings>

– and in Web.DEV.config you provide the connection string for the development environment and specify a matching pattern. In this case specify to match on the name attribute of the element, and all the other attributes you provide will replace those in the source (there are more complex transformations available):

Normal
0

false
false
false

EN-US
X-NONE
X-NONE

/* Style Definitions */
table.MsoNormalTable
{mso-style-name:”Table Normal”;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:””;
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin-top:0cm;
mso-para-margin-right:0cm;
mso-para-margin-bottom:10.0pt;
mso-para-margin-left:0cm;
mso-pagination:widow-orphan;
font-size:11.0pt;
mso-bidi-font-size:10.0pt;
font-family:”Calibri”,”sans-serif”;
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:”Times New Roman”;
mso-bidi-theme-font:minor-bidi;}

<connectionStrings>

<add name=db1

connectionString=Data Source=.\SQLEXPRESS;Initiali Catalog=xyz;Integrated Security=SSPI;

xdt:Transform=SetAttributes xdt:Locator=Match(name)/>

</connectionStrings>

Switch to the DEV build type, right-click the web project and select “Build Deployment Package” to generate a config file for dev which contains the transformed node with the connectionString attribute from the transform file and the providerName attribute from the source file:

Normal
0

false
false
false

EN-US
X-NONE
X-NONE

/* Style Definitions */
table.MsoNormalTable
{mso-style-name:”Table Normal”;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:””;
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin-top:0cm;
mso-para-margin-right:0cm;
mso-para-margin-bottom:10.0pt;
mso-para-margin-left:0cm;
mso-pagination:widow-orphan;
font-size:11.0pt;
mso-bidi-font-size:10.0pt;
font-family:”Calibri”,”sans-serif”;
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:”Times New Roman”;
mso-bidi-theme-font:minor-bidi;}

<connectionStrings>

<add name=db1

connectionString=Data Source=.\SQLEXPRESS;Initiali Catalog=xyz;Integrated Security=SSPI;

providerName=System.Data.SqlClient />

</connectionStrings>

All straightforward, and the deployment package VS builds is used with the WebDeploy tool, and makes it all very simple. The actual config file will be created in obj\<Configuration>\TransformWebConfig\transformed. You can get the same result from MSBuild by building the solution file with the property DeployOnBuild=True.

The actual transform logic is all in the TransformXml MSBuild task from Microsoft.Web.Publishing.Tasks.dll. So you can utilise the same functionality for generating any config file with a simple MSBuild script:

Normal
0

false
false
false

EN-US
X-NONE
X-NONE

/* Style Definitions */
table.MsoNormalTable
{mso-style-name:”Table Normal”;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:””;
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin-top:0cm;
mso-para-margin-right:0cm;
mso-para-margin-bottom:10.0pt;
mso-para-margin-left:0cm;
mso-pagination:widow-orphan;
font-size:11.0pt;
mso-bidi-font-size:10.0pt;
font-family:”Calibri”,”sans-serif”;
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:”Times New Roman”;
mso-bidi-theme-font:minor-bidi;}

<UsingTask TaskName=TransformXml AssemblyFile=bin\Microsoft.Web.Publishing.Tasks.dll/>

<Target Name=GenerateConfigs>

<MakeDir Directories=$(BuildOutput) Condition=!Exists(‘$(BuildOutput)’)/>

<TransformXml Source=BTSNTSvc.exe.config

Transform=BTSNTSvc.exe.$(Configuration).config

Destination=$(BuildOutput)\BTSNTSvc.exe.config/>

</Target>

You’ll have to manually create the source and transform files for each environment, but you can maintain the naming convention so the pattern is consistent across your Web projects and other config targets. One thing the transform doesn’t do is render the runtime value of MSBuild properties – so if you want to include the build version number in an attribute of the config file, then you’ll need a custom step before calling TransformXml to parse the property values.

For application config files you can have this step in your build prior to creating MSIs, so that the MSI has the correct config values when deployed. For external configs – if you need to populate say machine.config or BTSNTSvc.exe.config – you can create the configs in the build and have a manual deploy step to overwrite the files, or if you’re brave you could create an MSI which just contains the config files and overwrites the targets on install.

Note that Microsoft.Web.Publishing.Tasks.dll is part of VS 2010 and not part of MSBuild (default install location: C:\Program Files\MSBuild\Microsoft\VisualStudio\v10.0\Web), so you will need to be licenced to use the assembly on your build server.

This is an excellent way to centralise all your environment variables in source control along with the project code, and removes the risk of manual config updates as part of deployment.