Transform and Deployment
The first build configuration in our team city project built, tested, analyzed, and packaged our application for deployment. It created a set of artifacts that we can use to deploy this version of our application to each of the target environments.
Next we need to actually deploy our application. This process requires two steps:
- Apply config transformations
- Deploy the package
Setting up the Transform and Deploy Build Configuration
One of the first things you will notice about the transform and deploy build configuration in our Team City project is that it does not have any VCS roots. This is because it is unnecessary for these tasks to pull down the source and rebuild the application. All they need is the artifacts of the we created in our build and package build configuration. To access these artifacts, all we need to do is add them as dependencies for our configuration (steps #6):

As you can see in the image above, we need to be sure to depend on the three artifacts we created in our original build and package configuration.
Applying MSBuild Config Transformation without a Full Build
Since the artifacts necessary to deploy our application were created in the package step, it is unnecessary for us to rebuild our application. Instead we just need to modify the web.config file appropriately for the target environment. There is a very simple MSBuild target that will allow us to do this without a full build:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<Project DefaultTargets="Transform" | |
xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |
<UsingTask TaskName="TransformXml" | |
AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/> | |
<Target Name="Transform"> | |
<TransformXml Source="$(TransformSourcePath)Web.config" | |
Transform="$(TransformSourcePath)Web.$(Configuration).config" | |
Destination="$(PackagePath)Web.config" | |
StackTrace="false" /> | |
</Target> | |
</Project> |
This target takes four inputs and uses those to transform the base web.config using the appropriate transformation:
- Source – This is the relative path to the base web.config file. We packaged this and the transformation files as artifacts of our original package build configuration. They are included and available here because they are a dependency of our build configuration.
- Transform – This is the relative path and file names of the transformations (you can see the provided $(Configuration) switch is being used to determine the correct transform file to use.
- Destination – The destination for our new configuration file once it has undergone transformation. This is the location of the package we intend to deploy.
- StackTrace – Whether or not we would like a stack trace made available.
Here is the actual MSBuild command that is run by Team City:

Once this task is completed then we have a package with the following properties:
- A fully optimized release build.
- A web.configuration file that is correct for the target of our deployment.
- Only the files and folders necessary to run this application on a hosted environment.
Now all that’s left is to deploy the application…
Deploying with MSDeploy
Our tool of choice for deploying Microsoft Web applications to IIS is MSDeploy (and I strongly recommend it to the reader). You could easily use XCOPY, ROBOCOPY, or your copy file tool of choice, but MSDeploy offers a much more robust set of features and is tailored to deploying IIS assets. For more information on MSDeploy you can go to the official MSDeploy support site.
The build configuration for this step is extremely simple:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" -verb:sync -source:contentPath="%teamcity.build.workingDir%\%env.PackagePath%\" -dest:contentPath="%env.DestinationSite%",computername="%env.DestinationServer%" |
Great series Dave, my only recommendation is to put the MSBuild/MSDeploy commands (with command line parameters) into a batch file and keep the batch file in source control. This way your build configuration changes are tracked.
Thanks Chuck! Good point and something I’ve been considering.
One thing to keep in mind is that Team City does a great job of keeping revision history for all aspects of your build. You can see a full history of all of your changes right in the Team City UI. Because of this, it doesn’t seem necessary to add your build scripts to a source control repository just for revision history. I think it is probably better to just let Team City do its job and revision your build configurations. Source repositories for versioning source code and the build configuration to manage and version your build and deployment setups.
In general, I think it might be best to keep all of the build artifacts separate from the source repository. If I was going to keep build artifacts in source control then I would prefer to do it in a separate repository than my source code. I’ve even been trying to come up with a way to remove the .msbuild files from the source repository.
Hey Dave,
Is there supposed to be some info at the end on how the deployment build step is configured?
Thanks for the article… Do you have a copy of the transform.msbuild file you use that you can share?
Hi Kevin. It was actually in the article as a gist, but at some point the blog engine started handling the gist includes differently so it wasn’t showing. I have fixed all of the includes in that series of posts, so the source files are now showing. Please let me know if you need more info. Thanks!
David
Hi thanks for a great article. I have followed the article but having trouble deploying.
Can you please take a look at my stackoverflow question http://stackoverflow.com/questions/40404969/using-msdeploy-exe-to-deploy-folder-to-remote-site
Hi
Great articles, but i have one questions. I done quite get what env.PackagePath and enc.TransformSourcePath should point to?
Hi David–
Thanks for the great article. This saved me hours of work! I like and agree with your separation of “build” and “deploy”. I got my site deploying to our development, staging, and production sites in a number of hours thanks to you.
Thanks,
Brad