The web.config XDT transformations used in Visual Studio’s web projects are great for ensuring you don’t end up releasing say, a release version of your code pointing to the test database (yeah, that one with all the amusing names and phrases in it). Unfortunately this functionality wasn’t extended to the app.config. Luckily though we can add it in with minimal hassle, read on for the knowledge.
A quick pre-warning
The visual studio team are working on putting this functionality into the next version as standard, and the hacks we are putting into place here could make the upgrade a bit trickier. Personally I think that undoing these changes later is a small price to pay for the benefits you’ll get now. Just don’t come hunting me down when visual studio 2012/13/whatever gets released!
Setting your project up for transformations
This section is all about setting up the project as a whole. I’d advise doing this on a clean project and then using this as your project template so that it’s all ready and waiting for you.
Firstly, you’ll need to create a new Windows Service project. Now right click on the project in Solution Explorer and select Unload Project. This will grey out the project and mark it as unavailable. Now right click again and select Edit [projectname]:
This will load up the msbuild file which defines your project. All of the funky stuff we’re about to do will happen in here. Don’t worry if you don’t know much (or anything) about msbuild though, you’ll pick it up quickly.
Take a look at the first PropertyGroup node at the top of the file. This is defining some top-level information for the compiler to use. Add the following at the end of it. Right after the FileAlignment node:
This will be used by the existing transformations functionality to know which files to transform. Next, scroll right to the bottom of the file. You should see an Import node pointing to Microsoft.CSharp.Targets. These import nodes work just like a using statement in c# - we’re importing some existing functionality. So add a new Import node below to bring in the web publishing stuff, which includes the transformation targets:
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets" />
This is actually all we need to do to get transforms happening when you build against the TransformWebConfig target, but currently they won’t be written to your output directory. Instead they will appear under obj\x86\Debug\TransformWebConfig. We just need to do a little bit of msbuild code to copy them to the output directory for us.
Right at the bottom of the file, just before the closing </Project> tag enter the following:
<CallTarget Targets="TransformWebConfig" />
This creates our own target, which runs the hacked TransformWebConfig target and then copies any created transformation over the version in our build output path – easy!
Gotcha – OutputPath vs OutDir (MsBuild junkies only!)
It is important that you use the OutDir value to copy the transformed config to here. OutputPath will work fine for local builds but if you try and automate it through TFS Team Build it will mysteriously disappear. Using OutDir will work fine though.
Adding config transformation files
We’re ready to actually add our config files now so exit the msbuild file and reload the project. Create two config files called App.config and App.Debug.config. In the properties for each ensure their Build Action is set to Content so that they get picked up by the TransformWebConfig target. Next open the App.Debug.config and modify the Configuration with a new namespace declaration:
This will tell the TransformWebConfig target that this is an XDT transformation rather than a normal config file. Add a transform to the file too so that we can test that everything is working (I’m going to assume you know how to use the transforms if you’re reading this!).
Building the project
Now all we need to do is run the build. For this you’ll need to open the visual studio command prompt and navigate to the folder containing you project file. Enter the following (assuming your project file is called FakingWebConfigService.csproj):
msbuild FakingWebConfigService.csproj /t:TransformAppConfig
With any luck you should see a load of output messages followed by a green Build Succeeded message. Take a look at your project output and your transformed config file will be sat there – magic!
Tidying up solution explorer
We’ve got a nicely working solution now, but it would be nice if we could get the transforms to be a step down the ‘tree’ from the main config file like they do in web apps. This only requires a little bit of hacking so let’s do it now. Unload the project and open its msbuild file. Locate the Content node for each of your transform files and tell it to depend on the main App.config file:
That’s it! Reload the project and your transforms should show up in the right place.
How to fire off the transformation process
There are a few options for when to fire off the transform process which I’ll go over briefly:
Keep running it from the command line
Perfectly reasonable, but it means each member of the team needs to know the target name and how to use the command line msbuild. It also means specifying configurations manually – you’d have to add a /p:Configuration=Release argument to the msbuild call to do a release version for example. But it works and it’s better than what we had before.
Run it on every build
We can make it run on every build simply by adding an AfterTargets attribute to our Target node in the msbuild file:
<Target Name="TransformAppConfig" AfterTargets="Build">
Again, this works fine and is more foolproof than running from the command line. My issue with it is that web projects don’t do this on build – only deploy. I think the inconsistency is asking for trouble, but I’m sure it works fine for some teams.
Run it as part of a TFS Build
You can get Team Build to run the TransformAppConfig target for you as part of a central build. This is much better than the previous two options (in my opinion anyway) and is easy to set up. I’ll assume that you know how to set up a new build definition (if not check out the first part of my post on Continuous Deployment). All you then need to do is go into the Process tab, drop down the advanced node and enter /t:TransformAppConfig /p:Configuration=YOURCONFIGURATION into the MsBuild Arguments box:
When you run the build now it will transform your configs for you.
Include it in your WiX installer
This is my favoured solution. It is perfectly possible to cause the config transformations to happen as part of the build cycle of a WiX installer. I’ll went through this technique in my next post on creating Windows Service installers in WiX which should be posted in the next week or so. If you’re new to WiX then get with the program and check out my introductory series on WiX and deployment.
Thank you ladies and gentlemen, and goodbye!
Hopefully this post has been of help to those of you frustrated by the partial config transformation implementation in Visual Studio 2010. If you’d like to be informed when the next step posts on this topic are released you could always subscribe to my RSS feed.
Full source code is available here: FakingWebConfigService.zip (29.68 kb)
Did you find this post useful or interesting? I'd be really grateful if you could return the favour by clicking this google link: