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?
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.
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>
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...
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>
Inside the website.publishproj
file, ensure the configuration is set to Release:
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
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>
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.
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.