28

It doesn't seem to be possible to change the Build Configuration of Visual Studio 2010 Website Projects (as opposed to Visual Studio Web Applications), and changing the Build Configuration is a key part of enabling Web.config transformations (it's not possible to change the configuration to anything except Debug).

How do I get Web.config transformations to work with Visual Studio 2010 Website projects if it's not possible to change the Build Configuration?

Community
  • 1
  • 1
Ryan Shripat
  • 5,574
  • 6
  • 49
  • 77
  • Newer versions of Visual Studio support Web.config transformations in Web Site Projects. See [daniel's answer](https://stackoverflow.com/a/59813923/2615878) below for instructions on how to create the Web.*.config files. – Mike Grove aka Theophilus Sep 17 '20 at 18:15

6 Answers6

9

I'd prefer not to use entire an Web Application Project solution out of box. My solution is to use the XmlTransform task defined in Microsoft.Web.Publishing.Tasks.dll directly (this task is the core of WebConfigTransformation) This way it is flexible enough and does exactly what you expect it to do. For example here is the WebSiteTransformator.csproj I'm using for transforming web.config.

Here also is an example of flexibility that is impossible to reach with original WebConfigTransformation: it takes web.Template.config, applies web.$(Configuration).config over it and writes web.config. This allows us to add web.config itself into ignore list in source control. It is still valid csproj to be referenced by website:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <SchemaVersion>2.0</SchemaVersion>
    <OutputType>Library</OutputType>
    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
    <OutputPath>$(TEMP)\TransformWebConfig\bin</OutputPath>
    <BaseIntermediateOutputPath>$(TEMP)\TransformWebConfig\obj\</BaseIntermediateOutputPath>
    <IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
    <WebFolderName>$(SolutionDir)\MyWebSite\</WebFolderName>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="Dummy.cs" />
  </ItemGroup>
  <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <Target Name="BeforeBuild">
    <TransformXml Source="$(WebFolderName)Web.Template.config"
                  Transform="$(WebFolderName)Web.$(Configuration).config"
                  Destination="$(WebFolderName)Web.config" />
  </Target>
</Project>
Jacob
  • 2,212
  • 1
  • 12
  • 18
Andriy K
  • 3,302
  • 31
  • 42
  • I need to test this, it's very interesting! So you're saying I just need to add something similar to the UsingTask and TransformXml tags to my Website project's .csproj? – Ryan Shripat Apr 05 '11 at 17:01
  • If yours website project contains .csproj, I guess you should have it out of the box. This is still external project to be set as dependency for website, kind of solution level website BeforeBuild event. And it works, I swear:) (Actually this is the real piece of my current code base, just with MyWebSite instead of real folder name). – Andriy K Apr 07 '11 at 08:30
  • 2
    I just found out better way to make solution-wide build events: [MSBuild: Extending the solution build](http://sedodream.com/2010/10/22/MSBuildExtendingTheSolutionBuild.aspx) – Andriy K Apr 19 '11 at 17:55
6

I found a pretty good blog post describing a solution to this here: http://andrewtwest.com/2010/02/25/using-web-config-transformations-in-web-site-projects/

In short: create an empty project (as long as it is not another website project) in your solution that contains the website. The empty project will give you access to msbuild through its project file, which will allow you to perform transforms on your website web.config.

porusan
  • 918
  • 6
  • 6
  • That's a good hack, but I doubt I'll be implementing it... thanks anyway! – Ryan Shripat Feb 23 '11 at 13:39
  • 2
    Yea, it pretty much sucks that you have to resort to such a hacky approach to integrate msbuild, or even use that web.config transform feature, with website projects. I'm avoiding website projects and going to use web application projects as much as I can in the future. – porusan Feb 23 '11 at 17:43
4

I used a slightly alternative approach. Still a bit of a hack, but I think a lot more straightforward. This worked for me, but obviously there are a lot of different configurations available so I can't guarantee it'll work for everyone. This revolves around the way that a website is first packaged up in to your AppData folder before being published...

  1. Manually add a Web.Release.config file to the website and add the necessary transforms - obviously there's no 'Add Config Transform' option for websites, hence having to do this manually. Example Web.Release.config:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
        <appSettings>
            <add key="MySetting" value="NewValue" xdt:Transform="Replace" xdt:Locator="Match(key)" />
        </appSettings>
        <system.web>
            <compilation xdt:Transform="RemoveAttributes(debug)" />
        </system.web>
    </configuration>
    
  2. Inside the website.publishproj file, ensure the configuration is set to Release:

    <Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
    
  3. Add the following to the very bottom of website.publishproj (just before </Project>):

    <Target Name="AfterBuild">
      <MakeDir Directories="$(PackageArchiveRootDir)\..\CSAutoParameterize\original" />
      <TransformXml Source="Web.config" Transform="Web.$(ConfigurationName).config" Destination="$(PackageArchiveRootDir)\..\CSAutoParameterize\original\Web.config" StackTrace="false" />
    </Target>
    
Moo
  • 849
  • 7
  • 16
3

Create a publish profile in VS 2017 and then right click on the .pubxml profile in App_Data\PublishProfiles and select Add Config Transform.

See https://social.msdn.microsoft.com/Forums/vstudio/en-US/31f41991-abb2-41de-ad0b-c1379cc7c806/vs-2013-express-for-web-webconfig-transforms?forum=visualstudiogeneral&prof=required

daniel
  • 481
  • 1
  • 4
  • 5
2

As mentioned in Andriy's comment above, Solution wide build events definitely seems like a cleaner way to do this.

I am adding this as a separate answer, as it gets a little lost in the comment, but IMHO is the best answer. Props to Andriy K and Sayed Ibrahim.

Jacob
  • 2,212
  • 1
  • 12
  • 18
James
  • 7,877
  • 7
  • 42
  • 57
1

If you would prefer not to need a Web.Template.config, I used this:

<PropertyGroup>
    <_tempSourceFile>$([System.IO.Path]::GetTempFileName())</_tempSourceFile>
    <_tempTransformFile>$([System.IO.Path]::GetTempFileName())</_tempTransformFile>
</PropertyGroup>

<Copy SourceFiles="$(ProjectDir)Web.config" DestinationFiles="$(_tempSourceFile)"/>
<Copy SourceFiles="$(ProjectDir)Web.$(Configuration).config" DestinationFiles="$(_tempTransformFile)"/>

<TransformXml Source="$(_tempSourceFile)"
              Transform="$(_tempTransformFile)"
              Destination="$(ProjectDir)Web.config"
              StackTrace="false" />

Adapted from an answer here.

Community
  • 1
  • 1
Simeon Bartley
  • 136
  • 1
  • 4