当构建过程使用强名称对程序集进行签名时,如何使InternalsVisibleTo起作用?

6
在我们的商店中,我们使用Cruise Control和MSBuild来自动化构建产品作为持续集成的一部分。构建的一部分是对程序集进行签名,以使其具有强名称。在我们开发本地项目文件时,它并没有指定签名,因为这是由MSBuild脚本覆盖的。这一切都很好,直到我决定引入需要我使用"InternalsVisibleTo"属性的单元测试。我还开始使用一个很好的开源库,该库的单元测试也使用了这种技术。这意味着,在我的机器上,我可以更新AssemblyInfo.cs以使用以下语句:
[assembly: InternalsVisibleTo("MyProject.Tests.UnitTests")]

一切都很好。

然而,检查此内容会导致构建失败,因为构建机器会对程序集进行签名,该行需要更新为以下内容:

[assembly: InternalsVisibleTo("MyProject.Tests.UnitTests, 
             PublicKey="magic key here..)"]

我有点想不签名程序集就结束了。然而,“签名程序集是最佳实践”(重复这个口号3次),如果我们从中得到任何好处,我不想放弃它。
我们不安装到GAC,我们不特别关心篡改,不必担心使用我们库的第三方,我们更新应用程序时同时更新所有文件。最明显的好处是支持中的某个人不能将某个随机版本的程序集复制到运行时文件夹中,并使事情在短时间内似乎正常工作。
我不想打开涉及手动更改约100个项目文件以启用签名的问题。我也不想通过将应该是内部的东西标记为公共来破坏事情,我不想进入绑定重定向和我不想删除单元测试。
我希望具有无需强名称的所有便利性和具有强名称的所有好处(如果有的话),而且我不想创建很多额外的工作。这太过分了吗?
这篇文章很好地描述了问题和解决方案,但我不太擅长MSBuild脚本,无法充分利用它:

http://social.msdn.microsoft.com/forums/en-US/msbuild/thread/02df643c-956a-48bd-ac01-4a1016d91032/

这个问题的合适解决方案是什么?

欢迎任何意见和讨论。

2个回答

5

使用与禁用开发人员构建签名相同的结构来定义编译器符号,例如 DO_NOT_SIGN,然后在您的 AssemblyInfo.cs 中使用此代码:

#if DO_NOT_SIGN
[assembly: InternalsVisibleTo("MyProject.Tests.UnitTests")]
#else
[assembly: InternalsVisibleTo("MyProject.Tests.UnitTests, PublicKey="magic key here..)"]
#endif

在我个人看来,这比在构建脚本中修改源代码更加优雅。

谢谢你的回复,skolima。我想对于这个解决方案,我的问题是现在我必须手动进入X个文件并创建这个结构,无论需要多少次,我或其他人必须记住在新项目上执行它,并且在键被更改的情况下有一些重新工作的可能性。它确实有一个好处,那就是对任何人都是可见和可理解的,而不是埋在MSBuild脚本中的神秘东西,而不是每个人都非常了解。 我认为懒惰的程序员会选择使用构建脚本,因为我们的脚本中已经有了框架。 - Wes

4
您可以在编译之前将关键信息打补丁到源文件中。
下面的示例使用来自MSBuild Community TasksFileUpdate和(非常简单的)正则表达式将关键信息打补丁到C# AssemblyInfo.cs文件中。
<ItemGroup>
    <AssemblyInfoFiles Include="$(MSBuildProjectDirectory)**/AssemblyInfo.cs"/>
</ItemGroup>
<FileUpdate
  Files="@(AssemblyInfoFiles)"
  Regex='(\[assembly:\s*InternalsVisibleTo\(\"[\w.]*\")(\)\])'
  ReplacementText='$1, PublicKey="$(StrongNamingPublicKey)"$2' />

然而,我认为修改项目以始终进行强名称签名将是消除开发和部署环境之间另一个差异的更干净的解决方案,并且可以很容易地编写脚本。


谢谢Thomas,我会尝试这个并在成功后接受它作为答案。到处进行强签名存在一些问题,主要是我不确定如何编写脚本来进行更改,也不想手动操作。我们现有的构建脚本是由一个比我更懂MSBuild的人编写的,他处理签名,我只需要稍作调整而不是引入重大更改。 - Wes
我从来没有让这个工作,但我会将其标记为答案。 没有工作的是名为AssemblyInfoFiles的ItemGroup...它总是空的...有什么想法吗? 包含模式基本上就是你发布的内容...谢谢! - Wes
1
上面的ItemGroup假设要修补的AssemblyInfo.cs文件位于构建脚本下的一个目录中;**通配符将匹配当前目录下的任何目录。有关MSBuild包含语法的更多信息,请参见如何:选择要构建的文件 - Thomas Gerstendörfer

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