Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
How to enable transformations on build with Visual Studio

#Transform web.config on build

  1. Unload the project
  2. Edit .csproj
  3. Append figure 1 to the end of the file just before </Project>; v12.0 my change depending on your version of Visual Studio
  4. Save .csproj and reload
  5. Open configuration manager
  6. Add a new Configuration Name: Base. Copy settings from: Release
  7. Copy the contents of your web.config
  8. Right click Web.Config > Add Config Transformation
  9. Overwrite the web.base.config with the contents of your clipboard
  10. From now on Web.Config will be overwritten using transformations.

For settings that apply to all cofigurations use Base
For settings that apply only to Release use Release
For settings that apply only to Debug use Debug

A helpful note to add to your projects [base|debug|release].config

<!-- web.base.config -->
<!-- web.debug.config -->
<!-- web.release.config -->

####Figure 1 Copy and paste:

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v12.0\WebApplications\Microsoft.WebApplication.targets" />
<Target Name="BeforeBuild">
    <TransformXml Source="Web.Base.config" Transform="Web.$(Configuration).config" Destination="Web.config" />

Found this from the Googlz. Pithy, brief, concise, well-formed, .. bravo.

FYI someone said elsewhere (I haven't validated) that in VS2013 (and/or perhaps .NET 4.5.x) you don't need the <Import ..> tag addition.

Threre are some NuGet packages that are modifying Web.config directly. In this case it's important not to forget to copy those changes to Web.base.config

Automating and putting into nested folder. Thanks again.

educit commented Feb 23, 2016

I used Visual Studio 2015 and as stimpy77 said we don't need the <Import ...> tag addition.
Instead it will likely be located under this:

FYI: To have this applied during the build rather than deploy phase, use the Slow Cheetah plugin; more info here:

Why use base? The following should work just fine:
<TransformXml Source="Web.config" Transform="Web.$(Configuration).config" Destination="Web.config" />

@nordquist you should use Web.config.base so that you're not committing the Web.config with the (potentially sensitive) transforms into source control

@nordquist yeah it's a nifty trick, but i'd ditch the web.base.config too -- it's abnormal, obtuse, and a solves a pebkac problem by introducing something abnormal, obtuse.. "be a rebel, conform;" i say. the existing industry convention is to have a default, and then transform the default for a particular environment/config/purpose. the default configs live in source control, don't require a build step to exist or be valid, and typically meet the needs of local hosting/debugging (e.g. valid for all developers that would need to punch F5 "out of the box" and expect everything to work.)

zleao commented Oct 20, 2016

Fast and helpful help to achieve web.config transformation on build! Thank you!

I think the main problem with transforming the Web.config file directly, is that the file handle is still open by the TransformXml task for read, when it tries to write it. The solution, is to add an extra copy (and delete) step in, to avoid the file handle collision:

  <!-- First, we extend the "BuildDependsOn" property with our custom target for applying the transform.
This is a cleaner/safer alternative to overloading the "AfterBuild" target: -->

  <!-- Now, down to business: this is our target for applying the config transform.
I've included some conditions, to help avoid the build from blowing up when a transform
doesn't exist for the current configuration: -->

  <Target Name="_VisualStudioApplyTransform">
    <!-- Transform the file out to a temp file, sourcing from our Web.config file: -->
    <TransformXml Source="Web.config" Transform="Web.$(Configuration).config" Destination="Web.config.temp"
                  Condition="Exists('Web.$(Configuration).config')" />

    <!-- Copy the temp file, back over the top of Web.config, the file handle opened by TransformXml is closed now: -->
    <Copy SourceFiles="Web.config.temp" DestinationFiles="Web.config"
          Condition="Exists('Web.config.temp')" />

    <!-- Cleanup after ourselves: -->
    <Delete Files="Web.config.temp" Condition="Exists('Web.config.temp')" />

urig commented Feb 13, 2017

First off, thanks for sharing this. It's awesome.
Does this "play nice" with "publish time" config transforms? Having applied @stimpy77's to a project, it looks to me that the transforms are not running when right-clicking the project and publishing it to Azure. Is there something I'm missing?

In VS Community Update 3, I get an "invalid child element" for TransformXml when using this verbatim... I also tried:

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\WebApplications\Microsoft.WebApplication.targets" />

to see if that made a difference, but it didn't. I can't seem to find any answers online! Anyone getting the same issue?

Based on <UsingTask> element, could be used with .xproj file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment