Search code examples
.netmsbuildmsbuildcommunitytasksxmlmassupdate

Using XmlMassUpdate to update all appSettings


I want to use the XmlMassUpdate task in MSBuild to update appSettings in all app.configs. The problem I have is that some of the app.configs don't have an appSettings element, and I can't get XmlMassUpdate to skip those.

Here's what I've got so far

<ProjectExtensions>
  <appSettings xmlns:xmu="urn:msbuildcommunitytasks-xmlmassupdate">
    <add xmu:key="key" key="SettingName" value="newSetting" xmu:action="update" />
  </appSettings>
</ProjectExtensions>
<Target Name="Change">
   <ItemGroup>
     <AppConfigFiles Include="$(SourceRoot)\**\App.config" />
   </ItemGroup>
   <XmlMassUpdate 
      ContentFile="$(SourceRoot)\%(AppConfigFiles.RecursiveDir)App.config"
      ContentRoot="/configuration/appSettings"
      NamespaceDefinitions="msb=http://schemas.microsoft.com/developer/msbuild/2003"
      SubstitutionsFile="$(MSBuildProjectDirectory)\SetConfig.proj"
      SubstitutionsRoot="/msb:Project/msb:ProjectExtensions/msb:appSettings" />
</Target>

It fails on one of the App.configs saying Unable to locate '/configuration/appSettings'


Solution

  • You need to do that in 2 steps:

    • Query the app.config to check if the tag /configuration/appSettings exists
    • Call XmlMassUpdate only on file with the tag

    <ProjectExtensions>
      <appSettings xmlns:xmu="urn:msbuildcommunitytasks-xmlmassupdate">
        <add xmu:key="key" key="SettingName" value="newSetting" xmu:action="update" />
      </appSettings>
    </ProjectExtensions>
    
    <Target Name="UpdateIfNecessary">
      <!-- Check if appSettings exists-->
      <XmlQuery XmlFileName="$(AppConfigFile)"
               XPath = "/configuration/appSettings">
       <Output TaskParameter="Values" ItemName="appSettings" />
      </XmlQuery>
    
      <!-- Replace if appSettings exists -->
      <XmlMassUpdate Condition="%(appSettings._innerXml) != ''"
        ContentFile="$(AppConfigFile)"
        ContentRoot="/configuration/appSettings"
        NamespaceDefinitions="msb=http://schemas.microsoft.com/developer/msbuild/2003"
        SubstitutionsFile="$(MSBuildProjectDirectory)\SetConfig.proj"
        SubstitutionsRoot="/msb:Project/msb:ProjectExtensions/msb:appSettings" />
    </Target>
    
    
    <Target Name="MassUpdate">
      <ItemGroup>
        <AppConfigFiles Include="$(SourceRoot)\**\App.config" />
      </ItemGroup>
    
      <!-- Execute UpdateIfNecessary for each app.config file -->
      <MSBuild Projects="$(MSBuildProjectFile)" 
               Targets="UpdateIfNecessary"
               Properties="AppConfigFile=%(AppConfigFiles.Fullpath)"/> 
    </Target>