Configuring SlowCheetah to transform your web.config in your MSBuild script

On one of the projects I was working with, we wanted to enable web.config transforms.. simple.  In our set-up we were using Jenkins as the CI server.  In their build process, they were doing a build (not a publish) and copying over the project.  On the server we were not allowed to install Visual Studio, so when I tried to manually do the transformation and call

  <UsingTask TaskName="TransformXml"  AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.Tasks.dll"/>
My local build would work but the server would fail with an "assembly could not be found" error.  After some Googling, it seemed the SlowCheetah Nuget package was released, which removed the Visual Studio requirement.  After installing it and reading, it just worked.. nothing happened.  The problem we had on our project was that, as we were only copying file and doing a remote build, the transforms were not being triggered. Our build script was roughly based on this article Using Custom Web.config Transformations in MSBUILD.  After some head scratching, I didn't really know how to kick off the transforms, so below gives a step-by-step overview in case you find yourself with the same issues:

Step One: Pass in the configuration in your CI server

msbuild Soltuion.sln /p:Configuration=Staging

Step Two: Add SlowCheeta Nuget into your solution

After doing this you should have some files in this directory packages\SlowCheetah.2.5.14\tools. Specifically 'SlowCheetah.Xdt.dll'

Update Your Build Scripts

After you have the Slow Cheeta assembly installed within your project the next step is to create/update the build script to tell the CI server to actually do the transforms. As all build scripts and configurations are different I'll try to give a basic overview of the process. The first thing we do is define the name of the web.config to transform. In TransformXml we tell the build server the location of the Slow Cheeta assembly to perform the transform As part of the build process a temporary copy of the web.config will be made, the transforms will be applied and then the temp file will replace the existing web.config. The locations of the existing web.config and the path to the temporary web.config are defined in ItemGroup. TransformWebConfig defines the actual meat and bones of the script. In here we grab the staging web.config and copy if to the temp location, defined in TempWebConfig. We then perform the transform using the Slow Cheeta assembly and override the original web.config after the process has finished. Finally we delete the temp web.config.

    <PropertyGroup Condition="'$(Configuration)' == 'Staging'">


   <UsingTask TaskName="TransformXml"  AssemblyFile="$(MSBuildProjectDirectory)\..\packages\SlowCheetah.2.5.14\tools\SlowCheetah.Xdt.dll"/>

    <OriginalWebConfig Include="$(WebDir)\Web.config"/>
    <TempWebConfig Include="$(WebDir)\Deployment\Web.Temp.config"/>

  <Target Name="TransformWebConfig">

      <Copy SourceFiles="@(OriginalWebConfig)" DestinationFiles="@(TempWebConfig)" />

      <Message Text="@(TransformInputFile)" />

      <TransformXml Source="$(TransformInputFile)"
                            StackTrace="$(StackTraceEnabled)" />

      <Delete Files="@(TempWebConfig)"/>


You should then be able to run your script using something like this:
msbuild t:/TransformWebConfig

Jon D Jones

Software Architect, Programmer and Technologist Jon Jones is founder and CEO of London-based tech firm Digital Prompt. He has been working in the field for nearly a decade, specializing in new technologies and technical solution research in the web business. A passionate blogger by heart , speaker & consultant from England.. always on the hunt for the next challenge

Back to top
var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-35662136-1']); _gaq.push(['_trackPageview']); (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + ''; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })();