Как я могу использовать задачи MSBuild 'afterbuild' для редактирования файла.config?

У меня есть.config в целевом проекте, и мне нужно добавить строку к нему программно через задачу MSBuild.

Псевдо-операции типа:

  • найти целевой файл.config
  • определить значение атрибутов для нового узла (например, "id" и "version" для узла "package")
  • вставить новый узел в правильный родительский узел
  • Сохранить изменения

Файл.config в $TargetProjectDir\Config\packages.config:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="ABC" version="1.1.0.4" />
  <package id="XYZ" version="2.0.0.0" />
</packages>

Должен выглядеть так потом:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="ABC" version="1.1.0.4" />
  <package id="XYZ" version="2.0.0.0" />
  <package id="CarDataWidget" version="3.0.0.0" />
</packages>

До сих пор я рассматривал использование "встроенных задач", задачи "EXEC" и "XmlPoke", но мне не удалось заставить их работать.

Вот моя попытка с XmlPoke и XmlPeek:

Я использовал следующую статью как источник информации о том, как добавить узлы в файл packages.config: http://weblogs.asp.net/bsimser/appending-nodes-in-xml-files-with-xmlpeek-and-xmlpoke-using-nant с использованием-Нан

  <Target Name="AfterBuild" DependsOnTargets="AddPackage">
  </Target>
  <Target Name="AddPackage">
    <!-- Load existing nodes into a Property -->
    <XmlPeek XmlInputPath="config/packages.config" Query="/packages/package" >
      <Output TaskParameter="Result" PropertyName="Peeked" />
    </XmlPeek>
    <Message Text="From Peek: $(Peeked)"></Message>

    <!-- Load new node into Property -->
    <PropertyGroup>
      <WidgetName>CarDataWidget</WidgetName>
      <WidgetVersion>2.0.0.0</WidgetVersion>
      <NewNode>&lt;package id&#61;&quot;$(WidgetName)&quot; version&#61;&quot;$(WidgetVersion)&quot; /&gt;</NewNode>

    <!-- Concatenate existing and new node into a Property -->
      <ConcatenatedNodes>$(Peeked)$(NewNode)</ConcatenatedNodes>
    </PropertyGroup>
    <Message Text="New pacakges: $(ConcatenatedNodes)"></Message>

    <!-- Replace existing nodes with concatenated nodes -->
    <XmlPoke Value="$(ConcatenatedNodes)" XmlInputPath="config/packages.config" Query="/packages">
    </XmlPoke>
  </Target>

Выход из вышеупомянутой сборки:

1>AddPackage:
1>  From Peek: <package id="ABC" version="1.1.0.4" />;<package id="XYZ" version="2.0.0.0" />
1>  New pacakges: <package id="ABC" version="1.1.0.4" />;<package id="XYZ" version="2.0.0.0" /><package id="CarDataWidget" version="2.0.0.0" />
1>  C:\_dev\CarDataWidget.csproj(184,14): 
    error MSB4094: "<package id="ABC" version="1.1.0.4" />;<package id="XYZ" version="2.0.0.0" /><package id="CarDataWidget" version="2.0.0.0" />" 
    is an invalid value for the "Value" parameter of the "XmlPoke" task. 
    Multiple items cannot be passed into a parameter of type "Microsoft.Build.Framework.ITaskItem".
1>
1>Build FAILED.

ВОПРОС: Как заставить его добавить в файл.config существующие узлы пакета???

3 ответа

У меня такая же проблема. Я нашел решение здесь.

Проблема в том, что XmlPoke рассматривает точку с запятой как разделитель значений.

Следует заменить это:

<NewNode>&lt;package id&#61;&quot;$(WidgetName)&quot; version&#61;&quot;$(WidgetVersion)&quot; /&gt;</NewNode>

С:

<NewNode>&lt%3Bpackage id&#61%3B&quot%3B$(WidgetName)&quot%3B version&#61%3&quot%3$(WidgetVersion)&quot%3 /&gt%3</NewNode>

Необходимо заменить каждую точку с запятой на последовательность %3B

Вот способ сделать это, используя MSBuild Extension Pack.

Установите пакеты и версии в группе элементов NewPackage, и она добавит их в файл XML.

<Project 
    ToolsVersion="4.0" 
    xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <Import Project="$(MSBuildExtensionsPath)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks" />

  <Target Name="Test" DependsOnTargets="AddPackage">
  </Target>

  <ItemGroup>
    <NewPackage Include="CarDataWidget">
        <Version>3.0.0.0</Version>
    </NewPackage>
    <NewPackage Include="FooBarWidget">
        <Version>1.2.3.4</Version>
    </NewPackage>
  </ItemGroup>

  <Target Name="AddPackage">

    <PropertyGroup>
        <InputFile>in.xml</InputFile>
        <OutputFile>out.xml</OutputFile>
    </PropertyGroup>

    <Copy SourceFiles="$(InputFile)" DestinationFiles="$(OutputFile)" />

    <MSBuild.ExtensionPack.Xml.XmlFile
      TaskAction="AddElement"
      File="$(OutputFile)"
      XPath="//packages"
      Element="package"
      Key="id"
      Value="%(NewPackage.Identity)" />

    <MSBuild.ExtensionPack.Xml.XmlFile
      TaskAction="AddAttribute"
      File="$(OutputFile)"
      XPath="//packages/package[@id='%(NewPackage.Identity)']"
      Key="version"
      Value="%(NewPackage.Version)" />
  </Target>
</Project>

Не надеясь разбудить старый поток. У меня был точный сценарий, когда мне пришлось добавить новые ключи в раздел appsettings в web.config. Я начал с кода OP и столкнулся с той же проблемой: в найденном значении, предотвращающем запись нового объединенного значения. Я исправил это, используя функцию Replace, чтобы удалить;

          <ConcatenatedNodes>$(Peeked)$(NewNode)</ConcatenatedNodes>          
          <!--in the concatenatednode, remove semicolon-->
          <ChangedPeek>$(ConcatenatedNodes.Replace(";",""))</ChangedPeek>
          <!-- Replace existing nodes with concatenated nodes-->
          <XmlPoke XmlInputPath="%(WebConfigFilesSolutionDir.FullPath)" Query="//appSettings" Value="$(ChangedPeek)" />

Для получения полного ответа о том, как добавить новый ключ в раздел настройки приложений в webconfig с помощью MSBuild, см. /questions/50284249/xmlpoke-dlya-dobavleniya-neskolkih-klyuchej-appsettings-ne-rabotaet/50284264#50284264

Взгляните на мой пост в блоге http://sedodream.com/2011/12/29/UpdatingXMLFilesWithMSBuild.aspx котором сравниваются следующие методы.

  1. Используйте SlowCheetah, чтобы преобразовать файлы для вас
  2. Используйте задачу TransformXml напрямую
  3. Используйте встроенную (MSBuild 4.0) задачу XmlPoke
  4. Используйте стороннюю библиотеку задач
Другие вопросы по тегам