webTiger Logo Wide

Per-Machine Web Config in ASP.NET Projects

ASP.NET Logo

When working on multi-developer projects, if each developer machine isn’t configured the same way developers can waste a lot of time editing connection strings, local machine name, and other settings when pulling code projects from source code control. On ASP.NET code projects, you can configure per-machine configuration overrides to overcome this.

Even though a potential solution to this issue is to use web.Debug.config and NOT check it into source code control, most developers forget and you end up with either a default file (which was created with the code project), or a specific version when a random developer checked it into source control for the first time.

Fortunately, there is also another way (for web projects at least).

Using a WPP (Web Publishing Pipeline) targets file, coupled with a local-only .config file (e.g. web.localmachine.config), we can define overrides to apply to the web.config file during the build process.

This allows us to define a local configuration per-developer-machine and then have it automatically applied to our code project.

The first step in the process is to create a WPP targets file. This is simply a text (XML) file with the same name as the code project but with the file extension replaced with .wpp.targets. For example:

Project File: MyCo.Sales.Fulfilment.csproj
Targets File: MyCo.Sales.Fulfilment.wpp.targetsCode language: plaintext (plaintext)

As briefly mentioned the WPP targets file is XML and needs to conform to a published schema. Here is example file content, that can probably be used with little or no modification in most cases:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup>
    <PrepareForRunDependsOn>
      $(PrepareForRunDependsOn);
      ApplyLocalMachineWebConfig;
    </PrepareForRunDependsOn>
  </PropertyGroup>

  <Target Name="ApplyLocalMachineWebConfig">
    <Message Text="Configuration: $(Configuration) - applying web.perMachine.config"/>
    <TransformXml Source="web.config" Transform="web.LocalMachine.config" Destination="web.config" />
  </Target>

  <Target Name="ExcludeCustomConfigTransformFiles" BeforeTargets="ExcludeFilesFromPackage">
    <ItemGroup>
      <ExcludeFromPackageFiles Include="web.LocalMachine.config"/>
    </ItemGroup>
    <Message Text="ExcludeFromPackageFiles: @(ExcludeFromPackageFiles)" Importance="high"/>
  </Target>
</Project>Code language: HTML, XML (xml)

The other file is simply a standard configuration transformation file (just like the web.Debug.config and web.Release.config files that are auto-created when you create a new code project). The file can be named anything but web.LocalMachine.config is fairly descriptive and is recommended if in doubt. Provide all the transformations you need to apply in the file and save the changes.

Here is an example where the SqlConnection connection string is being updated and the local machine name too.

<?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">
  <!--
    Replaces per-machine connection strings so main web.config doesn't have to be edited by individual developers.
    -->
  <connectionStrings>
    <add name="SqlConnection" 
      connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Sales;Integrated Security=SSPI;" 
      providerName="System.Data.SqlClient" 
      xdt:Transform="Replace"
      xdt:Locator="Match(name)"
      />
  </connectionStrings>
  <appSettings>
    <add key="MachineName"
      value="LAPTOP30MX2"
      xdt:Transform="Replace" xdt:Locator="Match(key)"/>
  </appSettings>
</configuration>Code language: HTML, XML (xml)

That’s it – per machine config that automatically applies whenever you build the code project.

If you are working with a source code control system, then adding those machine specific files to the ignore list is a good idea too.