Thursday 28 July 2011

Publishing a website to the filesystem with msbuild and config transforms

Ever since I read Scott Hanselman's post Web Deployment Made Awesome: If You're Using XCopy, You're Doing It Wrong I've wanted to leverage Visual Studio's config transforms, but never had the opportunity until last week. I also took the opportunity to investigate Web Deploy. Here's a summary of my findings:

On Web Deploy
I followed Troy Hunt's excellent series on this topic, in order to learn how to set up an end-to-end build process that uses Web Deploy. Whilst it is indeed an excellent technology, the following notes need bearing in mind:
  1. The target web site, file-system folder and app-pool must all exist to start with. I was quite disappointed to find this, as it means an alternative technology is required to create these in the first place (such as the MSBuild Extension Pack's Web tasks or MSDeploy).
  2. Visual Studio needs to "know" about all files and folders that need deploying. Most cases are covered by marking the file as either Content or as a reference. If your project had files copied into the distribution by either a pre or post-build event then these files won't be deployed.
On MSBuild
The build pipeline I was integrating into used MSBuild Extension Pack's web tasks to deploy to IIS. This meant that my part of the build had to create a transformed web-site as a complete file-set, ready to deploy. I achieved this using the following MSBuild command:

<MSBuild
   Projects="$(SolutionPath)"
   Targets="Clean;Rebuild;ResolveReferences;Package"
   Properties=
"Configuration=$(Configuration);
OutDir=$(MSBuildProjectDirectory)\bin\; 
AutoParameterizationWebConfigConnectionStrings=false;
_PackageTempDir=$(OutDir)"
/>


The items in italics are the important ones:
  1. Package invokes the package step (creating the web-site as a complete file-set), which includes transformation of web.config.
  2. _PackageTempDir=$(OutDir) tells msbuild where to place the resultant package.
  3. AutoParameterizationWebConfigConnectionStrings=false ensures that the package step fully transforms ConnectionString elements. Read more on what happens if this is omitted, or set to true at Troy Hunt's Stack Overflow question.