Setting up a Web.Config Transformation without a Solution Configuration or Publish Profile
Based on our build and deployment strategy, we only need two different sets of compiler options (Solution Configurations): Debug and Release. Having to create Solution Configurations or Publish Profiles just to allow for XML Web.Config transformations clutters our solution unnecessarily and could prove confusing to new developers joining a project: Why do we have all these solution configurations when we never use them? Why do I have these publish profiles? Should I be publishing this application from my development machine?
We never want developers publishing to any of the test or production environments directly from their development machine. All deployments should be automated by the build environment and should be carefully controlled and audited. It’s crucial that our build process be reliable and repeatable. We would never use these Solution Configurations or Publish Profiles, so why should we even have them?
We do however want to be able to use web.config transformations: They are in-band with the application, making it easy to see what configuration changes are being made based on the deployment environment. They are source controlled and applicable to a specific set of build artifacts. The tools in Visual Studio make it very easy to maintain and preview these transformation files.
As it turns out, it is also very easy to add configuration transform files without having a Solution Configuration or Publish Profile. All you need to do is add the transformation XML file to your application with the appropriate name: Web.<TargetEnvironment>.config and add it to your project. Now the transformation step above will be able to use this file to apply these transforms to your web.config file. Since it’s only doing the transform and not a full build, it doesn’t need all of the other solution configuration information, just the transform file.
Ahh, but wait, something is missing. The new file looks like a completely separate file in Visual Studio. It’s not nicely related to the base web.config and cannot be easily previewed:
This can be easily remedied by editing the project file. To do this, right click your project file and click Unload Project. Then right click the project file and select edit. This allows you to edit the project file XML (basically just a big MSBuild file). Then add the following XML under the Project node to associate your new transform file with the base web.config file:
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
Now the file is associated with the base web.config and can be previewed:
By setting up our builds and deployments in this manner we have improved our deployment strategy in several ways:
- Only necessary files – We are utilizing MSBuild’s publish / package feature to make sure we only deploy the assets of our web sites which are required for it to function correctly on a hosted environment.
- Same assets on all environments – We have one set of assets that are created by our main build process which are deployed out to all of the target environments. This improves the reliability of our process and gives us the confidence that the bits that were successfully tested are the same ones that are deployed to each of our environments.
- Config transformations – We are able to include web.config transformation files directly in our solution to make it easy to switch configuration settings for our deployment to different target environments. We are also able to do this without having to set up unnecessary Solution Configurations.
- No scripts – We were able to remove all of the scripts (rake, cmd, powershell) that we were previously using to build and deploy our application. These scripts had become quite large and complex. They contained significant amounts of project specific logic which made them difficult to reuse.
- Repeatable – Because none of the build steps require scripts or any complex dependencies this pattern should be easy for other team members to follow when setting up builds and deployments for other projects.
There are still a lot of other steps we could take to improve the build and deployment process. Things like server provisioning and dynamic code analysis could be very helpful. These may be good topics for more future optimizations of our build process (and possible blog posts). The changes outlined in this series of posts will make our build process more reliable and repeatable. Also, they make it easier for other developers on our team to use Team City quickly to create robust builds and deployments for other projects without having to understand complex and build-specific scripts.