Добавление события Postbuild в проект

Когда я генерирую проект C# (csproj файл), а затем скомпилировать его, msbuild как-то не распознает переменные $(ConfigurationName) а также $(ProjectDir) (и другие) в событии до и после сборки.

Когда я вручную перемещаю конфигурацию событий до и после сборки в сгенерированную .csproj далее, затем msbuild правильно распознает эти переменные.

Добавление builddevent к проекту - это последнее, что я делаю перед сохранением проекта.

Вот как я добавляю это:

using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;

private const string PreBuildEventFixture = "PreBuildEvent";
private const string PostBuildEventFixture = "PostBuildEvent";
private const string PreBuildEvent = "attrib -R \"$(ProjectDir)app.config\"";
private const string PostBuildEvent = "copy \"$(ProjectDir)app.config.$(ConfigurationName)\" \"$(TargetDir)\\$(ProjectName).dll.config\" \r\n attrib -R \"$(ProjectPath)\"";

public void AddBuildEvents(Project project)
{
    ProjectPropertyGroupElement propertyGroupElement = project.Xml.AddPropertyGroup();
    propertyGroupElement.AddProperty(PreBuildEventFixture, PreBuildEvent);
    propertyGroupElement.AddProperty(PostBuildEventFixture, PostBuildEvent);
}

Я получаю ошибку при запуске сгенерированного проекта через msbuild:

The command "copy "app.config." "\.dll.config"" exited with code 1

Когда я потом вручную редактирую .csproj файл (с помощью блокнота или другого текстового редактора), вырезайте событие до и после сборки и вставьте его под <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> элемент, то msbuild строит сгенерированный .csproj файл в порядке.

Каков наилучший способ добавить события сборки в .csproj файл, так что он заканчивается после Import элемент в результате XML?

Видимо, мой нынешний способ использования [ProjectPropertyGroupElement][1] запросив его у AddPropertyGroup свойства Xml объекта Microsoft.Build.Evaluation.Project - нет.

Пример проекта:

using System.IO;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;

class Program
{
    private const string PreBuildEventFixture = "PreBuildEvent";
    private const string PostBuildEventFixture = "PostBuildEvent";
    private const string PreBuildEvent = "attrib -R \"$(ProjectDir)app.config\"";
    private const string PostBuildEvent = "copy \"$(ProjectDir)app.config.$(ConfigurationName)\" \"$(TargetDir)\\$(ProjectName).exe.config\" \r\n attrib -R \"$(ProjectPath)\"";

    private const string ProjectFile = @"C:\test\TestProject\TestProject.csproj";

    static void Main(string[] args)
    {
        if (!File.Exists(ProjectFile))
            throw new FileNotFoundException("ProjectFile not found");

        ProjectCollection collection = new ProjectCollection();
        Project project = collection.LoadProject(ProjectFile);

        ProjectPropertyGroupElement propertyGroupElement = project.Xml.AddPropertyGroup();
        propertyGroupElement.AddProperty(PreBuildEventFixture, PreBuildEvent);
        propertyGroupElement.AddProperty(PostBuildEventFixture, PostBuildEvent);
        project.Save();
        collection.UnloadAllProjects();
    }
}

Действия по воспроизведению

  • Создать новый проект
  • Вручную добавьте файл app.config.debug, который должен отличаться от файла app.debug
  • Добавьте postbuildevent: copy "$(ProjectDir)app.config.$(ConfigurationName)" "$(TargetDir)\$(ProjectName).exe.config
  • Смотрите, что сборка проекта и правильный файл конфигурации применены
  • Удалите события до и после сборки с помощью блокнота (чтобы не оставлять следов)
  • Запустите пример проекта
  • Перезагрузите и соберите созданный вами проект.
  • Окно вывода теперь скажет The system cannot find the file specified.

2 ответа

Решение
var propertyGroupElement = project.Xml.CreatePropertyGroupElement();
project.Xml.AppendChild(propertyGroupElement);
propertyGroupElement.AddProperty(PreBuildEventFixture, PreBuildEvent);
propertyGroupElement.AddProperty(PostBuildEventFixture, PostBuildEvent);

Связанные с проектом макросы не анализируются, если они добавляются до фактического создания проекта (создание проекта включает добавление ссылок). Вместо того, чтобы использовать $(ProjectName)путь может быть построен с использованием переменных решения (которые уже существуют), например:

copy "$(SolutionDir)ProjectName\app.config.$(Configuration)" "$(SolutionDir)ProjectName\bin\$(Configuration)\ProjectName.dll.config"

Обратите внимание, что ProjectName - это фактическое имя проекта, жестко закодированное, но поскольку вы генерируете проект, его легко добавить.

Другие вопросы по тегам