如何在运行时读取给定项目中的 MSBuild 属性?

How to read a MSBuild property in a given project in runtime?

我想在单元测试中访问 MSBuild 变量,这是一个 .NET 4.5 class 库项目 (classic csproj),但我找不到任何讨论方法的文章将值从 MSBuild 传递到执行上下文中。

我考虑过在编译期间设置一个环境变量,然后在执行期间读取该环境变量,但这似乎需要一个自定义任务来设置环境变量值,我有点担心变量的范围(理想情况下,我只希望它对当前正在执行的项目可用,而不是全局可用。

是否有在运行时从 DLL 项目内部读取 MSBuild 属性 的已知解决方案? MSBuild 属性可以在执行期间以某种方式 "passed as parameters" 吗?

我想你有几个选择:

  • 使用环境变量,就像您已经建议的那样。执行此操作可能需要自定义任务,但它是 easy to do,您不需要任何额外的程序集。所需的全球知名度可能是一个棘手的问题;例如,考虑在 CI 机器上并行构建。
  • 在构建期间编写代码片段并将其包含到生成的程序集中(类似于您在评论中建议的 the link 下已经找到的内容。
  • 在构建期间编写一个文件(甚至 app.config),其中包含反映您需要的 MSBuild 属性的设置;在测试期间阅读那些 运行s.

(顺便说一句,没有意义的是,尝试在 运行 时间内再次读取 MSBuild 项目文件(使用 Microsoft.Build 框架)。这一次需要大量工作首先,恕我直言,收益微乎其微。 更重要的是,您很可能(取决于属性的复杂性和依赖性)需要确保您调用的 MSBuild 库具有与实际生成期间存在的相同属性。可以说,如果你是从这里开始的,那可能会让你退缩。)

最后两个选项最适合,因为它们具有相同的特征:它们的范围仅限于您当前拥有的 build/test 运行(即您可以并行 运行ning 构建无干扰)。

我可能会选择第三个,因为这似乎是最容易实现的。

事实上,我已经在我一直从事的一个更大的项目中这样做了。基本上,我们有不同的环境(数据库连接字符串等)并且 select 那些 作为 post 构建步骤,基本上将特定的 myenv.config 复制到 default.config。 测试只会查找名为 default.config 的文件并获取其中设置的任何设置。

我最终通过使用 .Net Core 项目中默认使用的相同代码生成任务使其工作。唯一的区别是我必须在 csproj 文件中手动添加 Target 才能工作,因为代码创建不是框架项目的标准:

<Target Name="BeforeBuild">
  <ItemGroup>
    <AssemblyAttributes Include="MyProject.SolutionFileAttribute">
      <_Parameter1>$(SolutionPath)</_Parameter1>
    </AssemblyAttributes>
  </ItemGroup>
  <WriteCodeFragment AssemblyAttributes="@(AssemblyAttributes)" Language="C#" OutputDirectory="$(IntermediateOutputPath)" OutputFile="SolutionInfo.cs">
    <Output TaskParameter="OutputFile" ItemName="Compile" />
    <Output TaskParameter="OutputFile" ItemName="FileWrites" />
  </WriteCodeFragment>
</Target>

带有 CompileFileWrites 的行可以很好地处理 clean 等(请参阅我上面评论中的链接答案)。其他一切都应该足够直观。

当项目编译时,一个自定义属性被添加到程序集中,然后我可以使用普通反射检索:

Assembly
    .GetExecutingAssembly()
    .GetCustomAttribute<SolutionFileAttribute>()
    .SolutionFile

这非常有效,让我可以避免对解决方案文件进行任何硬编码搜索。