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

Posted

技术标签:

【中文标题】如何将“InternalsVisibleTo”属性与强命名程序集一起使用?【英文标题】:How to use "InternalsVisibleTo" attribute with Strongly named assembly? 【发布时间】:2015-09-05 17:50:52 【问题描述】:

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

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

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

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

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

这篇文章说:

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

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

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

【问题讨论】:

我试过了。它说使用 SN.exe,但这仅在程序集被强签名时才有效。由于上述错误,我无法将我的程序集编译为强类型。 SN.exe 报错“.dll 不代表强命名程序集” 看来先有鸡还是先有蛋,需要other程序集的公钥。 您的“朋友”程序集必须经过严格签名才能在“内部可见”中使用,并且您需要该其他程序集的令牌。 我的单元测试程序集的公钥? 【参考方案1】:

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

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

通常,由于您将签署程序集,因此您会知道公钥。 IE。如果您有 snk 文件,则 sn -t youSnk.snk 将显示公钥。或者您可以按照Getting Public Key Token of Assembly Within Visual Studio 中的步骤配置您的VS 以显示任何使用sn -Tp path to assembly 从程序集中获取公钥的程序集的公共令牌。 (如果文档不见了,步骤复制到other answer to this question)

【讨论】:

那么哪一步需要Actual key,哪一步需要keyToken? @nl-x 您需要私钥+公钥(snk)来签署程序集,对于InternalsVisibleTo,您只需要公开内部组件的程序集的公钥令牌(不必与那个相同)用于签署当前程序集)。 所以我把我现有的 .snk 文件,我到 sn -p myfile.snk public.key 然后 sn -tp public.key 获取我的公钥(320 个字符)和公钥令牌(16 个字符)......所以你在 AssemblyInfo.cs 中说我应该有 [assembly: InternalsVisibleTo("Reviews.Tests, PublicKey= 然后是短令牌吗?我问是因为令牌对我不起作用,但整个公钥都可以。 运行sn -t youSnk.snk 时出现错误“无法将密钥转换为令牌--无效的程序集公钥”。我改为运行sn -Tp path to assembly,并且成功了。另外,我在Developer Command Prompt for VS 2017 中运行了sn 命令,该命令已经安装在Start > Visual Studio 2017 中。【参考方案2】:

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


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

从我们钟爱的 IDE 中,转到“Tools > External Tools...”和“Add”具有这些设置的新工具:

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

应用/确定这些更改。

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

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

[程序集:InternalsVisibleTo("MyCompany.SolutionName.ProjectName, PublicKey=在此处粘贴您的公钥")]

/!\ 你必须从你的公钥中删除换行符。

它对我来说非常有效,所以希望它也能对你有用!

【讨论】:

对于其他感兴趣的人,我必须使用 NETFX 4.6.1 作为目录名称 @Kzrystof - 复制此步骤的文章写于 2008 年......所以这些步骤确实适用于 VS 2015。 效果很好,但我必须先成功构建解决方案至少一次 我在“NETFX 4.6.1 工具”中找到了这个 @DanielV 是的,每个 .NET 版本都有自己的工具(对此有专门的警告;))【参考方案3】:

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

将下面的这个类复制并粘贴到您的测试 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());
    

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

【讨论】:

以上是关于如何将“InternalsVisibleTo”属性与强命名程序集一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

什么时候应该使用 [assembly: InternalsVisibleTo()]?

Visual Studio 2017 和新的 .csproj InternalsVisibleTo

InternalsVisibleTo 带有“私人保护”

如何对 Moq 可见内部接口?

Moq 内部类和/或内部方法

如何在swift中使用其他属性将实例作为属性传递