VS 2010 web.config transformations are great.
Change your development web.config which looks like this:
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="ApplicationServices"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0">
by adding a Web.
DeployTest.config file which looks like this:
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings>
<add name="ApplicationServices" connectionString="Data Source=StaticVoidSqlServer;Initial Catalog=Northwind;Integrated Security=SSPI;" providerName="System.Data.SqlClient"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
</configuration>
Only by default it's tied up with the build configurations (Debug, Release etc) and the Web deploy story.
But I don't want a web deployment package. I want:
- a normal "Release" configuration build
- a directory containing all the website files that I can XCopy deploy (like old school Visual Studio 2008 publish)
- the web.config transformed with my custom "DeployTest" name.
Doing it this way means the web.DeployTest.config is not automatically nested under the web.config (and I should mark it as BuildAction=None).
But that's my requirements. So I wrote an MSBuild file.
Batch file (build.bat)
First here's a standard batch file, "build.bat", to launch it (I want MSBuild 4.0):
%systemroot%\Microsoft.Net\Framework\v4.0.30319\MSBuild.exe build.proj /t:Release & pause
MSBuild script (build.proj)
<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Release">
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
<PropertyGroup>
<!-- properties that are used in this build file - referenced as $(PropertyName) -->
<ProjectName>StaticVoid</ProjectName>
<DeployConfiguration>DeployTest</DeployConfiguration>
<PublishPath>$(MSBuildProjectDirectory)\..\Publish\</PublishPath>
<OutputPath>$(PublishPath)\StaticVoid\</OutputPath>
<PackagePath>$(PublishPath)\StaticVoidPackage\</PackagePath>
<TransformInputFile>..\StaticVoid\Web.config</TransformInputFile>
<TransformFile>..\StaticVoid\Web.$(DeployConfiguration).config</TransformFile>
<TransformOutputFile>$(OutputPath)\Web.config</TransformOutputFile>
<ImageResourcesPath>..\ImageResources</ImageResourcesPath>
</PropertyGroup>
<ItemGroup>
<ImageResources Include="$(ImageResourcesPath)\*.jpg" />
</ItemGroup>
<!-- targets -->
<Target Name="PublishWebsite">
<Message Text="Publishing Website" />
<RemoveDir Directories="$(PublishPath)"/>
<!-- do a deploy -->
<MSBuild Projects="..\StaticVoid\StaticVoid.csproj"
Properties="Configuration=Release;OutputPath=$(PackagePath);DeployOnBuild=true;DeployTarget=PipelinePreDeployCopyAllFilesToOneFolder;AutoParameterizationWebConfigConnectionStrings=false;_PackageTempDir=$(OutputPath)"/>
</Target>
<Target Name="Transform">
<!-- transform the web.config -->
<TransformXml Source="$(TransformInputFile)"
Transform="$(TransformFile)"
Destination="$(TransformOutputFile)" />
</Target>
<Target Name="BuildWebsite" DependsOnTargets="PublishWebsite">
<!-- we don't need the deployment package, we wanted the published files to copy manually -->
<RemoveDir Directories="$(PackagePath)"/>
<!-- copy the unmanaged resources -->
<Copy SourceFiles="@(ImageResources)" DestinationFolder="$(PublishPath)images" SkipUnchangedFiles="true" />
</Target>
<Target Name="Release" DependsOnTargets="BuildWebsite; Transform;">
</Target>
</Project>
A little explanation
The MSBuild task for the website project (StaticVoid.csproj) has a whole set of extra properties set which make it do a deploy.
(Broken here to be easier to read:)
<MSBuild Projects="..\StaticVoid\StaticVoid.csproj"
Properties="Configuration=Release;
OutputPath=$(PackagePath);
DeployOnBuild=true;
DeployTarget=PipelinePreDeployCopyAllFilesToOneFolder;
AutoParameterizationWebConfigConnectionStrings=false;
_PackageTempDir=$(OutputPath)"/>
The regular deployment package is written to $(PackagePath). I don't care about that, so I delete it.
The actual directory and files that I wanted are written to $(OutputPath) using the _PackageTempDir property.
For the transform, note the msbuild xml must have
Project ToolsVersion="
4.0"
and
<UsingTask TaskName="TransformXml"
AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
And then the transformation:
<TransformXml Source="$(TransformInputFile)"
Transform="$(TransformFile)"
Destination="$(TransformOutputFile)" />
with $(TransformFile) defined as
<TransformFile>..\StaticVoid\Web.$(DeployConfiguration).config</TransformFile>
Simply changing the DeployConfiguration property lets me have test and production builds which transform things nicely.
Update: the old _CopyWebApplication still works too
In Visual Studio 2008 you could use this task:
<MSBuild Projects="..\StaticVoid\StaticVoid.csproj"
Targets="ResolveReferences;_CopyWebApplication"
Properties="Configuration=Release;
WebProjectOutputDir=$(OutputPath);
OutDir=$(OutputPath)\bin\" />
This still works in Visual Studio 2010's MSBuild (and you don't have a package directory to delete).
The transforms can still be done manually.