10

We are setting up continuous integration with team city doing builds on check-ins. This works fine, however it always builds with default web.config, it does not transform with development environment specific web config. In Visual Studio, I have custom build configuration created for development. The web.development.config transforms correctly when I publish locally with development configuration selected, but this does not happen on the build server. In team city, as part of msbuild step I have created a build parameter sys.configuration and I am passing development as the value. But when it runs, the resulting web.config is not transformed with the development settings. I also tried setting the command line parameter to /p:configuration=development with no success.

Any help will be much appreciated.

Tim
  • 5,435
  • 7
  • 42
  • 62
jack
  • 1,488
  • 7
  • 25
  • 44

5 Answers5

23

We've been using publish targets in our web application projects and had seen that the build process was correctly transforming our web.config files, but when we moved the build to our CI server, the transforms were not being applied.

The MSBuild script were using was:

MSBuild.exe PATH_TO_PROJ.csproj /p:DeployOnBuild=true /p:PublishProfile=PUBLISH_TARGET

What we found was that we still needed to specify the Configuration as Debug or Release (even though this appears to be an attribute of the publish target.)

MSBuild.exe PATH_TO_PROJ.csproj /p:DeployOnBuild=true /p:PublishProfile=PUBLISH_TARGET /p:Configuration=Release

Brian Merrell
  • 1,144
  • 14
  • 20
12

I believe that for config transforms to occur when publishing using MSBuild rather than Visual Studio, you need to add a TransformXml task to your project.

This answer gives a guide on what you need to add, but to save a click:

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
<Target Name="BeforeBuild">
    <TransformXml Source="Web.config" Transform="Web.$(Configuration).config" Destination="Web.config" />
</Target>

You may need to change the path to the .targets file to be in line with whatever version is installed on your build server.

Community
  • 1
  • 1
thudbutt
  • 1,481
  • 1
  • 19
  • 32
  • This worked for me! Thanks for the help. All I did was, unload my project copied the above code to my project file. Note: By default "BeforeBuild" is commented. – jack Feb 17 '16 at 13:50
  • 8
    This solution will change the original web.config so when you try to build the project in VS it would ask you to overwrite the web.config every time. In my opinion it's not acceptable. – MichaelMao May 04 '17 at 02:48
  • 1
    improved version: `` – Adam Jan 19 '22 at 20:05
5

There are multiple conditions that need to be meet in order to generate transforms correctly

Inside .csproj make sure you have all of the following:

<Project> ...

      <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
      <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.targets" />
      <Target Name="SetTransformAppConfigDestination" BeforeTargets="PrepareForBuild" Condition="exists('Web.$(Configuration).config')">
        <PropertyGroup>
          <!-- Force build process to use the transformed configuration file from now on. -->
          <AppConfig>$(IntermediateOutputPath)$(TargetFileName).config</AppConfig>
        </PropertyGroup>
        <Message Text="AppConfig transformation destination: = $(AppConfig)" />
      </Target>
      <Target Name="TransformAppConfig" AfterTargets="PrepareForBuild" Condition="exists('Web.$(Configuration).config')">
        <TransformXml Source="Web.config" Transform="Web.$(Configuration).config" Destination="$(AppConfig)" />
      </Target>
    </Project>

Update your item group in .csproj file as well .

<ItemGroup> ...

<Content Include="Web.config">
      <SubType>Designer</SubType>
    </Content>
    <Content Include="Web.Debug.config">
      <DependentUpon>Web.config</DependentUpon>
    </Content>
    <Content Include="Web.Release.config">
      <DependentUpon>Web.config</DependentUpon>
      <IsTransformFile>True</IsTransformFile>
    </Content>
    <Content Include="Views\Web.config" />
    <Content Include="Views\Home\Index.cshtml" />
  </ItemGroup>

This will result in your config file to be nested in explorer view

enter image description here

Then make sure you have your path set correctly in properties -> build

enter image description here

Then add to your web.release.config tags for each node to be transformed

  1. xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"
  2. xdt:Transform="Replace"

to look like this:

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> 
   <appSettings xdt:Transform="Replace"> 
       <add key="VariableToBeTransformed" value="ValueToInsert"/> 
   </appSettings> 
   <system.web>
       <compilation xdt:Transform="RemoveAttributes(debug)" /> 
   </system.web>
</configuration> 

Also make sure your Solution configuration matches Debug/Release as intended enter image description here

Hope this helps everyone, you can do the same for app.config

matendie
  • 693
  • 7
  • 11
0

If you are using Visual Studio 2019 (Community edition in this example) your path to the latest msbuild.exe would look something like this: "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe"

and you can create an msstrong textbuild script in the following manner:

"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe" MyProject.csproj /p:DeployOnBuild=true /p:PublishProfile=Release /p:VisualStudioVersion=16.0 

where the parameter DeployOnBuild it triggers multiple targets after the build and among them there is a target that transformations the web.config. "The DeployOnBuild=true property essentially means "I want to execute an additional target when build completes successfully."

theCuriousOne
  • 1,022
  • 10
  • 22
0

The Publish function from Visual studio is using PublishProfiles/foo.pubxml in your project to determine your configuration, while MSBuild determine your configuration from project.sln.

You need to open Configuration Manager from Solution Explorer → Select Active solution configuration → Change the Configuration under Project contexts

saehan
  • 1
  • 1