如何将“InternalsVisibleTo”属性与强名称程序集一起使用

本文关键字:程序集 强名称 一起 属性 InternalsVisibleTo | 更新日期: 2023-09-27 17:57:05

我正在使用带有程序集的"InternalsVisibleTo"属性,以向我的单元测试项目公开内部方法/类。

我现在需要将该程序集安装到 GAC 中,因此需要为其指定一个强名称。当我尝试这样做时,我在Visual Studio中收到以下错误。

强名称签名程序集必须在其 InternalsVisibleTo 声明中指定公钥

谷歌搜索把我带到了下面的文章:

https://msdn.microsoft.com/en-us/library/bb763089.aspx

本文指出:

"确定强名称的好友程序集的公钥。"

本文没有说明如何确定公钥。在哪里可以找到程序集的公钥?另外,一旦我有了公钥,这是声明属性的正确方法吗?

[assembly: InternalsVisibleTo("Namespace.Assembly.Example.Name, PublicKey=ThePublicKey")]

如何将“InternalsVisibleTo”属性与强名称程序集一起使用


2019年5月更新:它与Visual Studio 2019完美配合。

<小时 />

2022 年 5 月更新 :正如@Igor梅萨罗斯所提到的,它也适用于 Visual Studio 2022。

<小时 />

对于任何使用Visual Studio 2017的人来说,都有最新的方法:

从我们心爱的 IDE 中,转到"工具>外部工具..."和"添加"具有这些设置的新工具:

  • 标题 : 获取公钥
  • 命令 : "C:''Program Files (x86)''Microsoft SDKs''Windows''v10.0A''bin''NETFX 4.6.2 Tools''sn.exe" (/!'' 选择与您的程序集 NETFX 版本匹配的 NETFX 工具版本,这里是 4.6.2)
  • 参数 : -tp $(目标路径)
  • 选中"使用输出窗口"复选框

应用/确定这些更改。

在"解决方案资源管理器"中,单击项目程序集名称,然后转到"获取公钥>工具"。"输出"窗口应显示(相当长的)公钥以及公钥密钥。

最后,在包含要公开的内部类(即测试的项目)的项目中,打开"AssemblyInfo.cs"文件并添加以下行:

[汇编:InternalsVisibleTo("MyCompany.SolutionName.ProjectName, PublicKey=将您的公钥粘贴到此处")]

/!'' 您必须从公钥中删除换行符。

对我来说非常有效,所以希望它也能为你解决问题!

若要将InternalsVisibleTo与强签名程序集一起使用,您的"友元"程序集也必须进行强签名。需要将测试程序集的公共令牌指定为InternalsVisibleTo值的一部分。

请注意,该属性不用于编译时程序集的实际验证 - 它仅指定运行时检查(以及友元程序集的编译时检查)应验证该标识。因此,如果您只需要编译主程序集,则可以指定任何公钥标记(例如,在 Web.Config 中的所有程序集引用上找到的 Microsoft 程序集中的一个公钥标记)。

通常,由于您将对程序集进行签名,因此您将知道公钥。 即,如果您有snk文件,则sn -t youSnk.snk将显示公钥。或者,可以按照在 Visual Studio 中获取程序集的公钥令牌中的步骤将 VS 配置为显示使用 sn -Tp {path to assembly} 从程序集获取公钥的任何程序集的公共令牌。(如果文档消失,步骤将复制到此问题的其他答案)

我使用了经典小说电影中的一个古老的好方法:"黑客总是在第二次尝试中猜测密码"。这是一种简单的技术,除了您已经拥有的工具之外,它不需要任何工具 - 一些单元测试框架。是的,必须对被测程序集进行签名,如此处多次提到。

将下面的此类复制并粘贴到测试 DLL 中。这是 xUnit 测试,但相同的方法适用于任何单元测试框架。

public class FindOutAssemblyPublicKey
{
    const string AssemblyPK = "Swordfish";
    /// <summary>
    /// Fake test to find out a correct PublicKey in InternalsVisibleTo for assembly under test.
    /// </summary>
    [Fact]
    public void AssemblyPublicKeyIsAsExpected()
    {
        byte[] publicKey = GetType().Assembly.GetName().GetPublicKey();
        var sb = new StringBuilder();
        foreach (byte @byte in publicKey)
            sb.AppendFormat("{0:x2}", @byte);
        // Set breakpoint here to find out what's in sb
        Assert.Equal(AssemblyPK, sb.ToString());
    }
}

这里的想法非常简单:测试在第一次运行时失败,但显示测试程序集的正确公钥。要仔细检查将"剑鱼"替换为您获得的实际值,请再次运行测试以确保它是绿色的并且您在这里。