Introduction

If you are working in a team with multiple developers, chances are you have different environment settings for things such as directory paths or database connection strings. One solution is for each dev to have a seperate configruation file (Web.config or App.config) which is not checked into source control. However this requires each dev to manually change their web.config when updates need to be applied (ie adding a new configuration setting).

A better solution would be to have the web.config in source control, and for it to be automatically modified with the developer specific settings at build time or at startup of the application while debugging.

Visual Studio can already do this update or transformation of the web.config on Publishing of web project via MSDeploy or ClickOnce. This is very useful for Release’s to QA or Production for instance, however it does not solve our problem of different settings per user while developing.

This post will cover the 3 easy steps needed to setup your Web project to automatically transform your web.config on Build (F5). You can do this once and then forget about it.

Step 1: Add a custom Solution Configuration

Find and open your Configuration Manager in Visual Studio. Add a new Solution Configuration.

Configuration Manager

Name the new configuration something meaningful, and preferably short with no special characters as it will be used in a filename later on. I suggest using your initials, as it makes it easy for all team members to identify the configurations later on.

New Solution Configuration

Ensure that your main web project (or app project) is set to build with your new project configuration when your configuration is used as the Active Solution Configuration. If you have any other projects in your solution they can be set to Debug or Release as required.

Configuration Manager

Step 2: Add a Config Transform.

Back in the Solution Explorer, right click on the Web.config and select the option to Add Config Transform.

Add config transform

This will create dependent Config files for each configuration you have in the active project, in this case Web.Debug.config, Web.Release.config and Web.JC.config.

Add all your transforms into your custom config file, such as connection strings or other settings. You can insert nodes, remove nodes and change attributes based on different criteria so this transformation is very powerful. You can also target any part of the web.config, not just the connection strings or app settings.

Below is my sample config file:

<?xml version="1.0" encoding="utf-8"?>
<!-- For more information on using web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <!-- In the example below, the "SetAttributes" transform will change the value of "connectionString" to use
         "ReleaseSQLServer" only when the "Match" locator finds an attribute "name" that has a value of "DefaultConnection". -->
    <connectionStrings>
      <add name="DefaultConnection" 
        connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True" 
        xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
    </connectionStrings>
</configuration>

Step 3: Update your .csproj file.

Now you need to run this transformation on build. Find and open your Web project file via Visual Studio. Alternatively edit the project file with your favourite text editor.

Edit Project File

Add the following snippet at the end of the project file, before the closing Project tag:

<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="ApplyWebConfigTransform" Condition="Exists('Web.$(Configuration).config')">
	<!-- Importance="High" for messages mean they show up in VS output window. -->
	<Message Importance="High" Text="Clearing read-only flag..." />
	<!-- TFS insists on marking all files in source control as read-only... -->
	<Exec Command="%SystemRoot%\system32\attrib -r Web.config" />
	<Message Importance="High" Text="Running configuration transform: $(Configuration) => Web.$(Configuration).config" />
	<TransformXml Source="Web.config" Transform="Web.$(Configuration).Config" Destination="web.config" />
</Target>
<Target Name="BeforeBuild" Condition="'$(PublishProfileName)' == '' And '$(WebPublishProfileFile)' == ''">
	<CallTarget Targets="ApplyWebConfigTransform" />
</Target>

In this snippet, we are importing a task from the Microsoft.Web.Publishing.Tasks.dll, and adding two targets.

The ApplyWebConfigTransform is where the magic happens. We run an xml transform before building the project but only if the project is not being built for publishing, and a Web.config transform file exists for the currently active Project Configuration.

Note that we are using the Web.config file as the source for the transform, so that the file is transformed “in place” rather than copied elsewhere and transformed along the way, as happens during Publishing. This also allows other tools such as the WCF Configuration Editor to edit the web.config file directly, and those edits will not be lost when the developer commits their changes to source control.

We also need to make sure that the file is writeable in case it has been marked as read-only.

Now build your project, and observe as your Web.config is updated. The VS Output window should show something similar to this:

Build output

Steps 1 and 2 should be repeated by each developer in the team when they checkout the solution for the first time.

Now your Visual Studio has been configured to apply your developer specific settings on Build!

References:

SlowCheetah - XML Transforms

SlowCheetah - Web.config Transformation Syntax now generalized for any XML configuration file

SlowCheetah - Support for web

ASP.NET: Transform Web.config with Debug/Release on Build



This post was originally published on Entelect’s internal Tech Blog, Yoda.