Stop XML transform during MSBuild step in Azure DevOps

09 Nov 2021

While setting-up release pipeline in Azure DevOps, you'll realize that it would be super useful if the stage-based XML transformation happens in release pipeline rather than the default build pipeline. This will enable you to do have a single build artifact, which can be transformed to respective release environment.

So, your release would do the actual transformation as follows

web.Release.config => web.config
web.Dev.config => web.config <!-- i.e., web.Environment.config transforms the web.config -->

Azure DevOps pipeline already has a release task that helps you with this. You just need to set enableXmlTransform parameter to true which would do an XML transformation before deploying the code to target environment.

- task: AzureRmWebAppDeployment@4
  displayName: 'Deploy ThemeHost app'
  inputs:
   ConnectionType: 'AzureRM'
   azureSubscription: 'MicrosoftAzureMySubscription'
   appType: 'webApp'
   WebAppName: 'myapp-dev'
   packageForLinux: '$(Pipeline.Workspace)/drop/myapp.zip'
   enableXmlTransform: true
   enableXmlVariableSubstitution: true

But, getting this to work as expected is bit of a challenge without proper instruction. I've gone through multiple documentation and Stack Overflow answers to come-up with following steps.

Issue 1

##[warning]Unable to apply transformation for the given package. Verify the following.
##[warning]1. Whether the Transformation is already applied for the MSBuild generated package during build. If yes, remove the <DependentUpon> tag for each config in the csproj file and rebuild. 
##[warning]2. Ensure that the config file and transformation files are present in the same folder inside the package.

This is because your Web.Release.config and Web.Dev.config won't be copied to output directory.

To fix this: Remove DependentUpon tag and Set the XML transformation files Build Action as "Content". So that, those configs are copied to published package.

<!-- Following lines -->
<Content Include="Web.config" />  
<None Include="Web.Dev.config">  
   <DependentUpon>Web.config</DependentUpon>  
</None>  
<None Include="Web.Release.config">  
   <DependentUpon>Web.config</DependentUpon>  
</None>  

<!-- Should be changed to -->
<Content Include="Web.config" />  
<Content Include="Web.Dev.config" />
<Content Include="Web.Release.config" />

Issue 2

Applying to 'compilation' element (no source line info)
File: , LineNumber: 4, LinePosition: 22, Message: Argument 'debug' did not match any attributes
Done executing RemoveAttributes
##[error]Error: XML transformation error while transforming D:\a\_temp\temp_web_package_2131565719454156\Content\D_C\a\1\s\AppSource\Layer\obj\Release\Package\PackageTmp\Web.config

This error happens because your build pipeline has already done a transformation and the target attribute was already removed. This shows up as an error while doing XML transform in the release step.

To fix this: You need to turn-off the XML transformation that automatically happens when MsBuild is run in your build pipeline.

For ASP.NET MVC projects, you need to specify /p:TransformWebConfigEnabled=false /p:AutoParameterizationWebConfigConnectionStrings=false parameter for MsBuild

- task: VSBuild@1
  displayName: 'Build Webapps'
    inputs:
      solution: 'MyApp/MyApp.sln'
      msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:TransformWebConfigEnabled=false /p:AutoParameterizationWebConfigConnectionStrings=false /p:PackageLocation="$(build.artifactstagingdirectory)\\"'
      platform: '$(buildPlatform)'
      configuration: '$(buildConfiguration)'
      msbuildArchitecture: 'x64'

For .NET Core projects, earlier you need to specify /p:TransformWebConfigEnabled=false. but later, this has been changed as /p:IsTransformWebConfigDisabled=true. Any one of these parameters used as part of arguments should work for you to stop the web.config transformation during build based on the MSBUILD version.

Issue 3

If you are using Multi-Stage YAML pipeline, you'll notice that web.release.config will be applied but your environment specific web.environment.config (e.g., web.dev.config) won't be applied. :)

So, solution for final piece of this puzzle is provided in Visual Studio - Developer Community forum. The pipeline expects an environment variable Release.EnvironmentName to be set your env name.

e.g., if your stage name is "Dev". Then you need to set a variable as shown below

variables:
 Release.EnvironmentName: Dev

Reference: https://developercommunity.visualstudio.com/t/multi-stage-yaml-pipeline-does-not-apply-environme/763175#T-N766663

These steps fixed my issues, and I could do all XML transformation and substitutions as expected.

Hope, you find this post useful.

Related Posts