HowTo: Web.config Transformations with MSBuild
With Asp.NET 4.0 a new feature named “Web.config Transformations“ was released. During my latest MSBuild Posts I showed you how to for example build a solution with pure MSBuild. Usually the web.config isn´t triggered and the WebApp works in debug Mod (worst case!). Because of this we need to trigger it manual in MSBuild.
How the output looks like till now
Take a look on this post to find out how to create a _PublishedWebsites folder where the WebApp. could be founded. But here you will find the Transformation-files too:
The main problem: The transformation of the mainly web.config doesn´t happen – the application runs with debug:
<compilation debug="true" targetFramework="4.0">
and then the call will look like this:
<TransformXml Source="Web.config" Transform="Web.Release.config" Destination="Web.transformed.config" />
BUT: that sucks! Am I right?
In the end I want the transformed file with the name “web.config”. the problem: TransformXml is buggy. During the build the task locked these 3 files. Anyway: We don´t want to change our web.config file in our solution. Because of this we need to create a copy of our sources and change them.
Scheme:
CopySource:
We copy our whole sources to another place for example one folder back in our own directory. I named it “ClientTemp”.
![]()
BeforeCompile:
Here in the BeforeCompile targets, which are located in Clienttemp, I´m able to do some changes like for example changing the AssemblyVersion while opening. At this place I´m used to open the TransformXml Task as well:
<TransformXml Source="..\MsBuildSample.WebApp\Web.config" Transform="..\MsBuildSample.WebApp\Web.$(Configuration).config" Destination="$(BuildDirFullName)MsBuildSample.WebApp\Web.config" />
Source&Transform are from the original branch and because of this we don´t need to take care of the lock.
Just the destination could be founded in our “cloned” folder. After this the “web.config” is transformed.
Build:
Here the mainly building process begins. The standard behavior is going to build the solution and pass the WebApp into the _PublishedWebsites OutDir.
—
Some other actions are able to follow. I´m going to delete the unused transformation files from the OutDir. (web.release.config / web.debug.config).
Result
It becomes a little bit trickier but the structure has her advantages as well. With this I´m able to work on my code during the building process (and before the compile) without changing the Source Code. It reminds me ( a little, little bit
of the functionality of TFS.
Complete buildscript:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Run"> <Import Project="$(MSBuildStartupDirectory)\Lib\MSBuild.Community.Tasks.Targets"/> <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" /> <PropertyGroup> <!-- After Compile: Result will be saved in OutDir --> <OutDir>$(MSBuildStartupDirectory)\..\..\ClientTemp\OutDir\</OutDir> <!-- Name of the BuildDir with the whole source code before the compile begins --> <BuildDirName>BuildDir</BuildDirName> <!-- Relativ part of the BuildDir --> <BuildDirRelativePart>..\..\ClientTemp\$(BuildDirName)</BuildDirRelativePart> <!-- Absolute part of the BuildDir--> <BuildDirFullName>$(MSBuildStartupDirectory)\$(BuildDirRelativePart)\</BuildDirFullName> <!-- Configuration --> <Configuration>Release</Configuration> <!-- Solutionproperties--> <SolutionProperties> OutDir=$(OutDir); Platform=Any CPU; Configuration=$(Configuration) </SolutionProperties> </PropertyGroup> <ItemGroup> <Solution Include="$(BuildDirFullName)MsBuildSample.sln"> <Properties> $(SolutionProperties) </Properties> </Solution> </ItemGroup> <Target Name="Run"> <Message Text="Run called." /> <CallTarget Targets="CopyToBuildDir" /> <CallTarget Targets="BeforeBuild" /> <CallTarget Targets="Build" /> <CallTarget Targets="Cleanup" /> <CallTarget Targets="Zip" /> </Target> <Target Name="CopyToBuildDir"> <Message Text="CopyToBuildDir called." /> <Exec Command="robocopy .. $(BuildDirRelativePart) /s /z /purge /a-:r" ContinueOnError="true" /> </Target> <Target Name="BeforeBuild"> <Message Text="BeforeBuild called." /> <Message Text="Transform Xml" /> <TransformXml Source="..\MsBuildSample.WebApp\Web.config" Transform="..\MsBuildSample.WebApp\Web.$(Configuration).config" Destination="$(BuildDirFullName)MsBuildSample.WebApp\Web.config" /> </Target> <Target Name="Build"> <Message Text="Build called." /> <MSBuild Projects="@(Solution)"/> </Target> <Target Name="Cleanup"> <Delete Files="$(OutDir)_PublishedWebsites\MsBuildSample.WebApp\Web.Release.config" /> <Delete Files="$(OutDir)_PublishedWebsites\MsBuildSample.WebApp\Web.Debug.config" /> </Target> <ItemGroup> <ZipFiles Include="$(OutDir)_PublishedWebsites\**\*.*" /> </ItemGroup> <Target Name="Zip"> <Zip Files="@(ZipFiles)" WorkingDirectory="$(OutDir)_PublishedWebsites\" ZipFileName="$(OutDir)Package.zip"/> </Target> </Project>
Democode:
In my demosolution I work with some help variables of MSBuild – don´t be scared
If you open the Samplecode:
D:\Samples\MsBuildSample ablegt findet Ihr das “BuildVerzeichnis” in D:\Samples\ClientTemp



Recent comments