【问题标题】:How to use "InternalsVisibleTo" attribute with Strongly named assembly?如何将“InternalsVisibleTo”属性与强命名程序集一起使用?
【发布时间】: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程序集的公钥。
  • 您的“朋友”程序集必须经过严格签名才能在“内部可见”中使用,并且您需要该其他程序集的令牌。
  • 我的单元测试程序集的公钥?

标签: c# .net-assembly


【解决方案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”替换为您所获得的实际值,请再次运行测试以确保它是绿色的。

【讨论】:

    猜你喜欢
    • 2011-03-31
    • 2010-11-06
    • 1970-01-01
    • 2010-12-06
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多