向项目添加 Postbuild 事件

4
当我生成一个C#项目(csproj文件)并编译它时,msbuild无法在预构建和后构建事件中识别变量$(ConfigurationName)$(ProjectDir)(以及其他变量)。
当我手动将预构建和后构建事件配置移动到生成的.csproj文件的下方时,然后msbuild会正确识别这些变量。
将buildevent添加到项目中是我保存项目之前做的最后一件事情。
这是我添加的方式:
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文件中的最佳方法,以便在生成的XML中出现在Import元素之后?
显然,我当前使用的方法是从AddPropertyGroup请求[ProjectPropertyGroupElement],并将其作为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
  • 检查项目构建并应用正确的配置文件
  • 使用记事本删除 pre- 和 postbuild 事件(这样不会留下任何痕迹)
  • 运行示例项目
  • 重新加载并构建您创建的项目。
  • 输出窗口将显示The system cannot find the file specified.

似乎文件 app.config 不存在(缺少 ConfigurationName)。你的手动构建事件是什么? - Patrick Hofman
首先添加它们并不重要,它们总是会被添加到引用和包含的<ItemGroup>上方,而应该在其后添加。 - Alfons
添加了示例项目。 - Alfons
2
你尝试过使用$(Configuration)而不是$(ConfigurationName)吗?我非常确定,MSBuild使用的是Configuration,而不是ConfigurationName。 - Novakov
之前没有尝试过这个方法,因为当我将预先和后置构建事件下移时,它是有效的,但$(projectdir)也没有被解析。我尝试了这个:echo $(ProjectDir) $(Configuration) $(TargetDir),它有所帮助,$(Configuration)得到了解析,但另外两个没有。 - Alfons
显示剩余4条评论
2个回答

5
var propertyGroupElement = project.Xml.CreatePropertyGroupElement();
project.Xml.AppendChild(propertyGroupElement);
propertyGroupElement.AddProperty(PreBuildEventFixture, PreBuildEvent);
propertyGroupElement.AddProperty(PostBuildEventFixture, PostBuildEvent);

2

如果在项目实际构建之前添加宏,与项目相关的宏将不会被解析(构建项目包括添加引用)。因此,可以使用已经存在的解决方案变量来构建路径,而不是使用$(ProjectName)。如下所示:

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

请注意,ProjectName是硬编码的实际项目名称,但由于您正在生成项目,因此很容易添加。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接