Как я могу использовать задачи 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><package id="$(WidgetName)" version="$(WidgetVersion)" /></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><package id="$(WidgetName)" version="$(WidgetVersion)" /></NewNode>
С:
<NewNode><%3Bpackage id=%3B"%3B$(WidgetName)"%3B version=%3"%3$(WidgetVersion)"%3 />%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 котором сравниваются следующие методы.
- Используйте SlowCheetah, чтобы преобразовать файлы для вас
- Используйте задачу TransformXml напрямую
- Используйте встроенную (MSBuild 4.0) задачу XmlPoke
- Используйте стороннюю библиотеку задач