Skip to content

Instantly share code, notes, and snippets.

@EdCharbeneau
Last active March 13, 2024 09:18
Show Gist options
  • Star 86 You must be signed in to star a gist
  • Fork 16 You must be signed in to fork a gist
  • Save EdCharbeneau/9135216 to your computer and use it in GitHub Desktop.
Save EdCharbeneau/9135216 to your computer and use it in GitHub Desktop.
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 CONFIG IN THIS PROJECT SHOULD ONLY BE MODIFIED BY -->
<!-- web.base.config -->
<!-- web.debug.config -->
<!-- web.release.config -->
<!-- CHANGES MADE DIRECTLY TO THE web.config WILL BE OVERWRITTEN -->

####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" />
</Target>     
@stimpy77
Copy link

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

@stimpy77
Copy link

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.

@andriy-f
Copy link

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

@stimpy77
Copy link

Automating and putting into nested folder. Thanks again. https://github.com/stimpy77/FastKoala

@educit
Copy link

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:

@JohnLBevan
Copy link

FYI: To have this applied during the build rather than deploy phase, use the Slow Cheetah plugin; more info here: http://stackoverflow.com/a/8841094/361842

@nordquist
Copy link

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

@glcheetham
Copy link

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

@wilson0x4d
Copy link

@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
Copy link

zleao commented Oct 20, 2016

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

@ivanpointer
Copy link

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: -->
  <PropertyGroup>
    <BuildDependsOn>
      $(BuildDependsOn);
      _VisualStudioApplyTransform;
    </BuildDependsOn>
  </PropertyGroup>

  <!-- 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')" />
  </Target>

@urig
Copy link

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 https://github.com/stimpy77/FastKoala 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?

@cssmonauts
Copy link

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?

@resnyanskiy
Copy link

FYI, https://marketplace.visualstudio.com/items?itemName=GolanAvraham.ConfigurationTransform
Based on <UsingTask> element, could be used with .xproj file.

@cemerson
Copy link

Awesome thanks for sharing. My VS 2015 version of this (I changed Source to just "Web.config" as I didn't have a "base" version:
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v14.0\WebApplications\Microsoft.WebApplication.targets" /> <Target Name="BeforeBuild"> <TransformXml Source="Web.config" Transform="Web.$(Configuration).config" Destination="Web.config" /> </Target>

@valbers
Copy link

valbers commented Apr 5, 2018

Thank you. Small correction:
"might change"
https://gist.github.com/valbers/2635267ef83cf976c7fc4b4beb516087

@mrpmorris
Copy link

This is great, thanks!

@gu1ms
Copy link

gu1ms commented Dec 14, 2018

I came here last year, once again I forgot the trick, so once again, thank you for this simple and efficient solution :)

@tenneyb
Copy link

tenneyb commented Jan 31, 2019

this doesn't work with VS 2017, at least for me is there a different import I need to add?

@IOrlandoni
Copy link

IOrlandoni commented Mar 5, 2019

this doesn't work with VS 2017, at least for me is there a different import I need to add?

You can parametrize the VS version in the <Import>'s project. Note the v$(VisualStudioVersion)

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

@artur-woocode
Copy link

You can also add <Copy SourceFiles="Web.Base.config" DestinationFiles="Web.config" /> and remove Web.config from project and gitignore it.

@jhudaverdi
Copy link

Do we need to use this approach for ASP.NET MVC projects in Visual Studio 2019? Or can we simply create multiple transformation using Configuration Manager in VS?

The other question is; as far as I know, By default, the web.config transforms are only used for publishing, not local debugging. So, what should we do in we want to use these created configs when running application in Visual Studio in Debug and Release configuration?

@jlgarcia-vs
Copy link

Do we need to use this approach for ASP.NET MVC projects in Visual Studio 2019? Or can we simply create multiple transformation using Configuration Manager in VS?

The other question is; as far as I know, By default, the web.config transforms are only used for publishing, not local debugging. So, what should we do in we want to use these created configs when running application in Visual Studio in Debug and Release configuration?

Hey, yes, you need this approach for VS2019. Just follow instructions in first post.

@chtenb
Copy link

chtenb commented Sep 16, 2021

How does one ensure the transformations do not run again at publish time? The publish step should simply take the Web.config produced by the build step as is, but it tries to re-apply the transformations defined in Web.Release.config.

@chtenb
Copy link

chtenb commented Sep 18, 2021

How does one ensure the transformations do not run again at publish time? The publish step should simply take the Web.config produced by the build step as is, but it tries to re-apply the transformations defined in Web.Release.config.

The following approach takes care of this:

https://stackoverflow.com/questions/8841075/web-config-transform-not-working/69232853#69232853

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