Web.config Transformations Aren’t as Tricky as You Think

Nov 14, 2011Sales Tips

Web.config transformations are an easy and elegant way to change what values will be in your web.config file depending on what ‘mode’ you publish in, all while leaving your development web.config file the same. A good example for where we heavily use web.config transformations is within our MusicMatters application. Due to the nature of MusicMatters, we have it set up for 3 different environments: Development, Testing, and Release.

A *very* stripped down version of our Development web.config file looks like this:

<?xml version="1.0" encoding="utf-8"?>
 <configuration>
 <configSections>
 <sectionGroup name="RequiresSSL">
 <section name="RequiresSSL_Files" type="System.Configuration.NameValueSectionHandler,system,Version=1.0.3300.0,Culture=neutral, PublicKeyToken=b77a5c561934e089,Custom=null" />
 <section name="RequiresSSL_Paths" type="System.Configuration.NameValueSectionHandler,system,Version=1.0.3300.0,Culture=neutral, PublicKeyToken=b77a5c561934e089,Custom=null" />
 </sectionGroup>
 </configSections>
 <connectionStrings>
 <add name="MusicMatters.Data" connectionString="Server=servername\serverinstance;Database=Testing4_MusicMatters;User ID=user;Password=password;" providerName="System.Data.SqlClient" />
 </connectionStrings>
 <appSettings>
 <add key="CampEnrollment.Email.Subject" value="Dev: MMAS Camp Enrollment" />
 </appSettings>
 <RequiresSSL>
 <RequiresSSL_Files>
 </RequiresSSL_Files>
 <RequiresSSL_Paths></RequiresSSL_Paths>
 </RequiresSSL>
 </configuration>

When the developer clicks on ‘start’, the application will use the values from above during debugging since no transformations are made until it is published regardless of the ‘mode’ you run it in. When we publish we do not want to point to the Testing4_MusicMatters database, we would want to point to the production database. By default, an asp.net application comes with Web.Debug and Web.Release transformation files, which allow you to change values from your base Web.config file based on which ‘mode’ you publish in.
There are many replacement types that we can accomplish, which can be found here. I’ll provide examples for the two I personally use the most, ‘Replace’ and ‘SetAttributes’.
An example of the Web.Release.config file looks like this:


 <?xml version="1.0"?>
 <appSettings>
 <add xdt:Locator="Match(key)" xdt:Transform="Replace" key="CampEnrollment.Email.Subject" value="MMAS Camp Enrollment"/>
 </appSettings>
 <connectionStrings>
 <add  xdt:Locator="Match(name)" xdt:Transform="SetAttributes" name="MusicMatters.Data" connectionString="Server=servername\serverinstance;Database=Production_MusicMatters;User ID=user;Password=password;" />
 </connectionStrings>
 <RequiresSSL  xdt:Transform="Replace">
 <RequiresSSL_Files>
 <add  key="campenrollment.aspx" value="true"></add>
 <add  key="process.aspx" value="true"></add>
 </RequiresSSL_Files>
 <RequiresSSL_Paths></RequiresSSL_Paths>
 </RequiresSSL>
 </configuration>
 <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">

If you look above, you can see a few xdt:Transform attributes scattered throughout the XML. These declare the type of transformation to occur on that specific node. When using Replace, you’re telling the application to completely replace the entire node with what you have set. The easiest example for this above is the <RequiresSSL> node. Putting xdt:Transform=”Replace” into that node states ‘take the node from the parent and replace it with this node’. In our final Web.config after publishing, the stripped output would now look like the following:

    <RequiresSSL>
    <RequiresSSL_Files>
      <add  key="campenrollment.aspx" value="true"></add>
      <add  key="process.aspx" value="true"></add>
    </RequiresSSL_Files>
    <RequiresSSL_Paths></RequiresSSL_Paths>
  </RequiresSSL>

If you have multiple possibilities with sibling elements (such as appSettings or connectionStrings), you can use xdt:Locator=”Match(key)” to locate a specific ‘key’ of an attribute:

<appSettings>
    <add xdt:Locator="Match(key)" xdt:Transform="Replace" key="CampEnrollment.Email.Subject" value="MMAS Camp Enrollment"/>
  </appSettings>

The above transformation states ‘Find the parent node based on the unique value of the ‘key’ attribute and replace it with this node’, and our output for this node becomes:

<appSettings>
    <add key="CampEnrollment.Email.Subject" value="MMAS Camp Enrollment"/>
  </appSettings>

So far we have replaced two entire nodes, but what if we don’t want to replace a node? What if we want to just set its value(s)? To accomplish this, we just need to use the xdt:Transform=”SetAttributes” transformation. This states to set all attributes that are within this node:

 

<connectionStrings>
    <add  xdt:Locator="Match(name)" xdt:Transform="SetAttributes" name="MusicMatters.Data" connectionString="Server=servername\serverinstance;Database=Production_MusicMatters;User ID=user;Password=password;"/>
  </connectionStrings>

The above transformation mixes up the xdt:Locator we’ve already covered as well as the new xdt:Transform. Our final output for our Web.config when publishing in ‘Release mode’ will be as follows:

 

 <?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <sectionGroup name="RequiresSSL">
            <section name="RequiresSSL_Files" type="System.Configuration.NameValueSectionHandler,system,Version=1.0.3300.0,Culture=neutral, PublicKeyToken=b77a5c561934e089,Custom=null" />
            <section name="RequiresSSL_Paths" type="System.Configuration.NameValueSectionHandler,system,Version=1.0.3300.0,Culture=neutral, PublicKeyToken=b77a5c561934e089,Custom=null" />
        </sectionGroup>
    </configSections>
    <connectionStrings>
        <add name="MusicMatters.Data" connectionString="Server=servername\serverinstance;Database=Testing4_MusicMatters;User ID=user;Password=password;" />
    </connectionStrings>
    <appSettings>
        <add key="CampEnrollment.Email.Subject" value="MMAS Camp Enrollment"/>
    </appSettings>
    <RequiresSSL>
        <RequiresSSL_Files>
            <add  key="campenrollment.aspx" value="true"></add>
            <add  key="process.aspx" value="true"></add>
        </RequiresSSL_Files>
        <RequiresSSL_Paths></RequiresSSL_Paths>
    </RequiresSSL>
</configuration>

Now whenever you publish you don’t need to manually make changes to the final Web.config file for the different environment, Visual Studio will take care of it for you!

Joel Reynolds

Joel helps ClickPoint achieve results by working with our corporate customers on custom requests. He has a commitment to understanding the needs of our customers thoroughly. His software reduces clutter and focuses on the power of intuitive design.