Xmlpoke to add multiple appsettings key doesn'

2019-08-22 13:57发布

问题:

I have a Msbuild target that gets executed successfully by adding a single key called 'ProjectID' to the appsetting section of web.config. Now am changing the behavior of this target by adding one more key 'ApplicationId' to the same appsetting section. The log shows the xmlpoke is executed for both. But only the projectID value is correctly replaced with every run.

(Excerpt from)PropertyGroup definition:

<?xml version="1.0" encoding="utf-8" ?>
   <Project ToolsVersion="15.0" DefaultTargets="Build" 
    xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
   <!-- Needs to be set! -->
   <ProjectID>4424cc12-4368-45ad-ad5b-19e821eb91d4</ProjectID>
   </PropertyGroup>

TargetCode:

<Target Name="UpdateConfigFilesInSolutionDir">
  <ItemGroup>
  <WebConfigFilesSolutionDir Include="$(SolutionDir)\**\*.config" />
  </ItemGroup>
  <Message Text="WebConfigFilesPath: %(WebConfigFilesSolutionDir.FullPath)" 
   Importance="high"></Message>
  <XmlPoke XmlInputPath="%(WebConfigFilesSolutionDir.FullPath)" 
   Query="//appSettings/add[@key='ProjectID']/@value" Value="$(ProjectID)" 
  />
  <XmlPoke XmlInputPath="%(WebConfigFilesSolutionDir.FullPath)" 
   Query="//appSettings/add[@key='ApplicationId']/@value" Value="SetAValue" 
  />
</Target>

Output log observed:

Using "XmlPoke" task from assembly "Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a". 2019-06-25 08:37:13,202 [9] DEBUG EP.BuildService.Handlers.ProjectBuildLogger [2e0de09a-3fd8-4932-bc1d-e3a66dd3c1ca] - Task "XmlPoke" 2019-06-25 08:37:13,203 [9] DEBUG EP.BuildService.Handlers.ProjectBuildLogger [2e0de09a-3fd8-4932-bc1d-e3a66dd3c1ca] - Replaced "value" with "4424cc12-4368-45ad-ad5b-19e821eb91d4". 2019-06-25 08:37:13,203 [9] DEBUG EP.BuildService.Handlers.ProjectBuildLogger [2e0de09a-3fd8-4932-bc1d-e3a66dd3c1ca] - Made 1 replacement(s). 2019-06-25 08:37:13,204 [9] DEBUG EP.BuildService.Handlers.ProjectBuildLogger [2e0de09a-3fd8-4932-bc1d-e3a66dd3c1ca] - Done executing task "XmlPoke". 2019-06-25 08:37:13,204 [9] DEBUG EP.BuildService.Handlers.ProjectBuildLogger [2e0de09a-3fd8-4932-bc1d-e3a66dd3c1ca] - Task "XmlPoke" 2019-06-25 08:37:13,204 [9] DEBUG EP.BuildService.Handlers.ProjectBuildLogger [2e0de09a-3fd8-4932-bc1d-e3a66dd3c1ca] - Made 0 replacement(s). 2019-06-25 08:37:13,204 [9] DEBUG EP.BuildService.Handlers.ProjectBuildLogger [2e0de09a-3fd8-4932-bc1d-e3a66dd3c1ca] - Done executing task "XmlPoke".

What I have tried so far:

  1. Originally was passing ApplicationId value in PropertyGroup. It didn't help.
  2. So hardcoding the value as seen in the code , Value="SetAValue" still not adding the key to appsetting.

回答1:

It turns out 'Add' in the xpath Query syntax doesn't add a key. Rather it adds or replaces values for the key if it exists. While this doesn't solve my problem of adding a app setting key during build, it at least gave me clarity on the capability of 'add' Useful links: http://sedodream.com/2011/12/29/UpdatingXMLFilesWithMSBuild.aspx http://samirvaidya.blogspot.com/2015/04/updating-webconfig-or-appconfig-file.html https://deejaygraham.github.io/2015/01/12/updating-web.config-settings-with-msbuild/

How to add a new key to the web.config during build (the answer to my original question)

A combination of XmlPeek and XmlPoke made it almost work, but with more work on sanitizing the data that gets written.

<Target Name="AddApplicationNodesInConfig">
<ItemGroup>
    <WebConfigFiles Include="$(SolutionDir)\**\Web.config" />
</ItemGroup>
<Message Text="WebConfigFilesPath: %(WebConfigFiles.FullPath)" Importance="high"></Message> 
<!--read applicationId and applicationName nodes from web.config if it exists-->
  <XmlPeek XmlInputPath="%(WebConfigFiles.FullPath)" Query="//appSettings/add" >
      <Output TaskParameter ="Result" PropertyName="Peeked" />        
  </XmlPeek>
  <Message Text="From Peek: $(Peeked)"></Message>
<!--Load new node into Property-->
  <PropertyGroup>         
      <ApplicationId>ApplicationId</ApplicationId>
      <ApplicationIdVal>100</ApplicationIdVal>
      <NewNode>&lt;add key&#61;&quot;$(ApplicationId)&quot; value&#61;&quot;$(ApplicationIdVal)&quot; /&gt;</NewNode>                         
      <!-- Concatenate existing and new node into a Property -->
      <ConcatenatedNodes>$(Peeked)$(NewNode)</ConcatenatedNodes>          
      <!--in the concatenatednode, remove semicolon-->
      <ChangedPeek>$(ConcatenatedNodes.Replace(";",""))</ChangedPeek>         
  </PropertyGroup>
  <Message Text="New pacakges: $(ChangedPeek)"></Message>
<!-- Replace existing nodes with concatenated nodes-->
 <XmlPoke XmlInputPath="%(WebConfigFilesSolutionDir.FullPath)" Query="//appSettings" Value="$(ChangedPeek)" />

The sole useful reference for adding a new key to web.config is How can I use MSBuild 'afterbuild' tasks to edit a .config file? My solution is built on top of this.