Transforming Config Files and XML Documents

When you’re deploying an application to different servers representing different environments, manually updating configuration settings can get very messy. In .NET applications, one of the ways to keep configuration settings under control is by using configuration transforms.

These transforms are a set of rules that define how the App.config or Web.config is to change (e.g. add appsettings, replace connection strings, etc) for the particular environment.

Syntax

Typically, when you create a new web application in Visual Studio, you’ll get a little more than just a Web.config file. In fact, if you expand the Web.config node in Solution Explorer, you’ll find that there are another two files: Web.Debug.config and Web.Release.config.

config-transform-web-default

As shown in the screenshot above, the Web.Release.config has a similar structure to Web.config itself; however it defines rules that work on the Web.config to produce a different result. In this case, there is a transform that will remove the debug attribute from the compilation node. You can see the result of this if you right click on Web.Release.config and select Preview Transform:

config-transform-preview

One of the most common places where transforms come in handy is to change the value of appsettings when deploying. Let’s say, for example, that we have the following setting in our App.config or Web.config file:

  <appSettings>
    <add key="SomeFilePath" value="myfile.txt" />
  </appSettings>

In our transform file (which so far has been Web.Release.config), we could define the following transform:

  <appSettings>
    <add key="SomeFilePath" value="C:\data\productionfile.txt"
         xdt:Transform="Replace"
         xdt:Locator="Match(key)" />
  </appSettings>

This tells the transform engine to look for the matching key (in this case “SomeFilePath”), and replace it with what is specified in the transform file:

config-transform-preview2

Similarly, it is very common to replace database connection strings depending on the environment. In fact, the default Web.Debug.config and Web.Release.config (shown earlier) explain in comments how to do this.

Other than removing attributes and replacing values, transforms support various other operations which allow insertion and removal of nodes and attributes. See Web.config Transformation Syntax for Web Project Deployment Using Visual Studio (official documentation) for detail.

Despite the title of that article, transforms may also be used with App.config files (for non-web projects) and just about any arbitrary XML file (although not quite in the same way as shown above). For web applications, Visual Studio provides some support for creating and previewing transforms. For other application types and XML documents, it is necessary to resort to other tools.

Tools

One of the simplest ways to apply config transforms (in particular, the Release transform) is to Publish your web application. This will compile your web application in Release mode, apply config transforms, and put it in the destination you specify.

Unfortunately, this approach has several drawbacks:

  • It is only suitable for web applications (not e.g. console applications).
  • It can’t be used for arbitrary XML files.
  • It can’t be extended to various different environments.
  • Being embedded in Visual Studio, it can’t be automated or integrated with a continuous integration system.

In recent years, Microsoft released an XML Document Transformation (XDT) library that enabled a variety of tools to run these transforms. This is available as the Microsoft.Web.Xdt NuGet package, and the source code is available on CodePlex.

The Web.config Transformation Tester is a web application that is useful for testing transforms. It uses XDT internally (see its source code) and can transform web and application configs as well as arbitrary XML files.

Config Transformation Tool (ctt) or XDT Transformation Tool is a command-line utility launched in 2010 also based on Microsoft’s XDT library. Although its Codeplex site says it’s still Alpha, I’ve used it to transform Web.config, App.config and XML files.

Say we have this Web.config file:

<?xml version="1.0"?>
<configuration>
  <appsettings></appsettings>
  <connectionStrings>
    <add name="foo" connectionString="value"/>
  </connectionStrings>
  <system.web>
    <customErrors mode="Off"/>
  </system.web>
</configuration>

…and we have this transform file called Web.Debug.config:

<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <appsettings>
    <add key="EnvironmentName" value="Debug"
        xdt:Transform="Insert" />
  </appsettings>
  <connectionStrings>
    <add name="foo" connectionString="differentValue"
        xdt:Transform="Replace" xdt:Locator="Match(name)" />
  </connectionStrings>
</configuration>

Then we can run ctt as follows:

ctt s:Web.config t:Web.Debug.config d:Web.Out.config i

I’m using the shorthand parameters here:

  • s: marks the source file.
  • t: marks the transform file.
  • d: marks the destination file.
  • i causes the output to be indented, because by default it’s minified and unreadable.

The output is as follows:

<?xml version="1.0"?><configuration>
    <appsettings>
        <add key="EnvironmentName" value="Debug" />
    </appsettings>
    <connectionStrings>
        <add name="foo" connectionString="differentValue" />
    </connectionStrings>
    <system.web>
        <customErrors mode="Off" />
    </system.web>
</configuration>

This also works on XML files. In fact, I’ve taken Microsoft’s sample books.xml file and applied the following transform file (books.transform.xml):

<?xml version="1.0"?>
<catalog xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
   <book id="bk113" xdt:Transform="Insert">
      <author>David Kushner</author>
      <title>Masters of Doom</title>
      <genre>Non-Fiction</genre>
      <price>10.95</price>
      <publish_date>2003-01-01</publish_date>
      <description>How two guys created an empire and transformed pop culture</description>
   </book>
</catalog>

This command applies the transformation:

ctt s:books.xml t:books.transform.xml d:books.out.xml i

As you can see, the insertion transform actually works:

config-transform-ctt-xml

Additionally, as a command line tool, ctt is great to automate transforms as part of a deploy script (e.g. in a batch file).

Aside from ctt, XDT’s open sourcing announcement lists a couple of other tools that use Microsoft’s XDT library. One is a Web Config Transform Runner which I haven’t tried but which is presumably similar to ctt. The other is SlowCheetah, a Visual Studio Extension which allows transforms to be previewed and added. The author discontinued development on SlowCheetah (see also Github thread) out of frustration that it wouldn’t become a first class citizen in Visual Studio, which ironically is what happened because the preview shown at the beginning of this article was created with Visual Studio 2015 without SlowCheetah installed.

Finally, this article would not be complete without a mention of TeamCity. Automating transformation of configuration settings is only one step in what should be a complete continuous integration solution running automated builds. TeamCity is just that, and it has support for transforms.

Leave a Reply

Your email address will not be published. Required fields are marked *