FAKE: Build ASP.NET projects with web.config transformation (and without knowing a tiny bit of F#)
This is a follow-up to my other FAKE posts:
- “FAKE: Building C# projects without knowing a tiny bit of F#”
- “FAKE: Running xUnit Tests with FAKE without knowing a tiny bit of F#”
- “FAKE: Create NuGet Packages without knowing a tiny bit of F#”
- “FAKE: Running MSTest Tests with FAKE without knowing a tiny bit of F#”
What’s the difference between a ASP.NET and other projects?
The most obvious difference is that the output is a bunch of dlls and content files. Additionally you might have a web.debug.config or web.release.config in your source folder.
Both files are important, because they are used during a Visual-Studio build as a Web.Config Transformation.
With a normal build the transformation will not kick in, so we need a way to trigger the transformation “manually”.
Project Overview
The sample project consists of one ASP.NET project and the .fsx file.
The “released” web.config should cover this 3 main transformation parts:
- DefaultConnectionString to ‘ReleaseSQLServer’
- No “debug”-attribute on system.web
- developmentMode-AppSetting set to ‘true’
Web.Release.config
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings>
<add name="DefaultConnection"
connectionString="ReleaseSQLServer"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
<appSettings>
<add key="developmentMode" value="true" xdt:Transform="SetAttributes"
xdt:Locator="Match(key)"/>
</appSettings>
<system.web>
<compilation xdt:Transform="RemoveAttributes(debug)" />
</system.web>
</configuration>
The FAKE script
We reuse the MSBuild-Helper from FAKE and inject a couple of “Publish”-related stuff, which will trigger the transformation.
A few remarks: In the “normal” WebDeploy-World you would have a PublishProfile and it would end up with a .zip-file and a couple of other files that fill in parameters like the ConnectionString. With this MSBuild command I mimik a part of this behavior and use the temporary output as our main artifact. In my most apps I use web.config transformations only for “easy” stuff (e.g. remove the debug attribute) - if you are doing fancy stuff and the output is not what you want, please let me know.
This MSBuild command should apply all your web.config transformations.
Publish a ASP.NET project
...
Target "BuildWebApp" (fun _ ->
trace "Building WebHosted Connect..."
!! "**/*.csproj"
|> MSBuild artifactsBuildDir "Package"
["Configuration", "Release"
"Platform", "AnyCPU"
"AutoParameterizationWebConfigConnectionStrings", "False"
"_PackageTempDir", (@"..\" + artifactsDir + @"Release-Ready-WebApp")
]
|> Log "AppBuild-Output: "
)
...
“AutoParameterizationWebConfigConnectionStrings” or how to get rid of $(ReplacableToken_…
Blogpost updated on 2016-07-18
A friend told me that his transformed web.config contained “$(ReplaceableToken_…)” strings. It seems that “connectionStrings” are treated specially. If you have a connectionString in your web.config and don’t set “AutoParameterizationWebConfigConnectionStrings=False” you will get something like that:
<connectionStrings>
<!-- Not the result we are looking for :-/ -->
<add name="DefaultConnection" connectionString="$(ReplacableToken_DefaultConnection-Web.config Connection String_0)" providerName="System.Data.SqlClient" />
</connectionStrings>
I would say this is not the result you are expecting. With the “AutoParameterizationWebConfigConnectionStrings=False” parameter it should either do a transformation or leave the default-connectionString value in the result.
Thanks to Timur Zanagar! I completely missed this issue.
Result
This build will produce two artifacts - the build-folder just contains the normal build output, but without a web.config transformation.
The other folder contains a ready to deploy web application, with the web.release.config applied.
<connectionStrings>
<add name="DefaultConnection" connectionString="ReleaseSQLServer" providerName="System.Data.SqlClient" />
</connectionStrings>
<appSettings>
...
<add key="developmentMode" value="true" />
</appSettings>
<system.web>
...
</system.web>
You can find the complete sample & build script on GitHub.