Transform app.config for 3 different environment

45.8k views Asked by At

I need to be able to transform my app.config file using msbuild. I can transform the file if it is called app.DEBUG.config or app.Release.config, but I cannot if I add one called app.PROD.config.

Using regular XDT transforms msbuild recognizes different web.config files if I select a different PublishProfile

 msbuild path.to.project.csproj Configuration=Release PublishProfile=DEV

Apparently app.config does not work with this same setup. I can always create a specific build configuration for a DEV.config setup but it seems useless to have a separate build confirm for one app. A hacky way to do so is to just copy the correct app.config per environment POST-BUILD.

I've attempted to use the SlowCheetah plugin, but this only seems to transform the default DEBUG and RELEASE config files, which is not appropriate since I have more than two environments. If I indeed am using this wrong, please let me know what parameter I should pass at to msbuild to choose my app.DEV.config.

The expected result would be that msbuild would transform the app.config according to the transform that is customized called app.DEV.config or the one customized for app.PROD.config. I would expect that there is a parameter that I can pass to msbuild that would allow me to use the Release configuration but a transform with a different name per environment.

4

There are 4 answers

2
Stuart Blackler On BEST ANSWER

This is what I use for this scenario:

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

  <!-- This target will run right before you run your app in Visual Studio -->
  <Target Name="UpdateWebConfigBeforeRun" BeforeTargets="Build">
    <Message Text="Configuration: $(Configuration) update from web.template.$(Configuration).config"/>
    <TransformXml Source="web.template.config"
              Transform="web.template.$(Configuration).config"
              Destination="web.config" />
    </Target>

  <!-- Exclude the config template files from the created package -->
  <Target Name="ExcludeCustomConfigTransformFiles" BeforeTargets="ExcludeFilesFromPackage">
    <ItemGroup>
      <ExcludeFromPackageFiles Include="web.template.config;web.template.*.config"/>
    </ItemGroup>
    <Message Text="ExcludeFromPackageFiles: @(ExcludeFromPackageFiles)" Importance="high"/>
  </Target>
</Project>

I have the following setup:

web.template.config
    - web.template.debug.config
    - web.template.production.config
    - web.template.release.config etc

Should work cross pc without the need for extra plugins etc. In your scenario, you need to edit the contents to say app. instead of web.

0
Jason Dimmick On

You can transform the app.config the same as the web.config. Use this nuget package located here https://github.com/acottais/msbuild.xdt

There are several other Nuget packages that will allow you to do this. I used this one the other day and it worked.

After installing it is as simple as Add-Transform from the VS Window.

0
Philippe On

I think what is confusing is that we have the ability to make compile-time config transformations and then we have deployment-time config transformations.

In general, you use compile-time config transformations to make changes to your locally-defaulted config file so that it is appropriate for a DEBUG or RELEASE configuration (or any custom configuration you define). For web.config, the tooling is built-in. For app.config, the SlowCheetah Visual Studio extension brings the same capability that we have for web.config to app.config. An example of a config transform for a RELEASE configuration is to remove the debug attribute on system.web compilation.

Deployment-time config transformations are manipulations of the config file while deploying to a specific environment (e.g. QA, PROD). Database connection strings need to change, service endpoints change, etc... For web.config, MSDEPLOY is the IIS tool of choice. For app.config, it seems we need to rely on installer technology. There are different tools for this, like WIX for example.

Anyway, I hope this short explanation of the distinction between compile-time and deployment-time config transformations helps explain why the toolset is fragmented. For more in-depth analysis, you can refer to a blog post I made on this subject: http://philippetruche.wordpress.com/2012/07/11/deploying-web-applications-to-multiple-environments-using-microsoft-web-deploy/

If choosing to use the WIX toolset to produce installers, refer to Creating Multi-Environment Windows Installers with Visual Studio 2012 and Wix.

4
Nirav Mehta On

App.config transforms

To test if transforms work you have to use real transforms. Insert-transform with appSettings block is maybe simplest one. I tested with following configuration files.

App.config:

<?xml version="1.0" encoding="utf-8" ?><configuration>  <appSettings>    <add key="FirstName" value="Gunnar"/>  </appSettings></configuration>

App.Release.config

<?xml version="1.0"?><configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">  <appSettings>    <add key="LastName" value="Peipman" xdt:Transform="Insert"/>  </appSettings></configuration>

Configuration file after transform:

<?xml version="1.0" encoding="utf-8" ?><configuration>  <appSettings>    <add key="FirstName" value="Gunnar"/>    <add key="LastName" value="Peipman"/>  </appSettings></configuration>

Making App.config transforms work

Let’s see how to do it with console application.

  1. Add App.config and App.Release.config to your project and fill them with content given above..
  2. Unload console application project.
  3. Right-click on project name and select "Edit <project file name>".
  4. Project file is opened as XML-file and you can see what is inside it.
  5. Before closing tag of first property group add the following line:

    <ProjectConfigFileName>App.Config</ProjectConfigFileName>
    
  6. Find <ItemGroup> where App.Config is defined (<None Include="App.Config" />) and add the following block after App.Config node:

    <None Include="App.Release.config"> 
        <DependentUpon>App.Config</DependentUpon>
    </None>
    
  7. Find first <Import Project= node and add the following import as last one to list:

    <Import Project="$(VSToolsPath)\Web\Microsoft.Web.Publishing.targets" Condition="'$(VSToolsPath)' != ''" />
    <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets" Condition="false" />
    
  8. To the end of file, just before tag, paste the following block of code:

    <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
    <Target Name="AfterCompile" Condition="exists('app.$(Configuration).config')">
      <TransformXml Source="app.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config" Transform="app.$(Configuration).config" />
      <ItemGroup>
        <AppConfigWithTargetPath Remove="app.config" />
        <AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
          <TargetPath>$(TargetFileName).config</TargetPath>
        </AppConfigWithTargetPath>
        <AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
          <TargetPath>$(TargetName).vshost$(TargetExt).config</TargetPath>
        </AppConfigWithTargetPath>
      </ItemGroup>
    </Target>
    
  9. Save project file, close it and reload it.

When loading project again Visual Studio may ask you about some modifications to file so all versions from Visual Studio 2010 to current are able to use your project file with no modifications to it. Agree with it because then you don’t have dependencies to Visual Studio versions.