我正在尝试使用InternalsVisibleTo assembly属性使我的单元测试项目可以看到.NET类库中的内部类。出于某种原因,我不断收到一条错误消息:

  

'MyClassName'由于其保护级别而无法访问

两个程序集都已签名,并且我在属性声明中列出了正确的密钥。有什么想法吗?

有帮助吗?

解决方案

您是否完全确定属性中指定了正确的公钥? 请注意,您需要指定完整的公钥,而不仅仅是公钥标记。它看起来像:

[assembly: InternalsVisibleTo("MyFriendAssembly,
PublicKey=0024000004800000940000000602000000240000525341310004000001000100F73
F4DDC11F0CA6209BC63EFCBBAC3DACB04B612E04FA07F01D919FB5A1579D20283DC12901C8B66
A08FB8A9CB6A5E81989007B3AA43CD7442BED6D21F4D33FB590A46420FB75265C889D536A9519
674440C3C2FB06C5924360243CACD4B641BE574C31A434CE845323395842FAAF106B234C2C140
6E2F553073FF557D2DB6C5")]

它是320左右的十六进制数字。不确定为什么需要指定完整的公钥 - 可能只使用其他程序集引用中使用的公钥标记,这样可以更容易欺骗朋友程序集的身份。

其他提示

另一种可能的<!>“; gotcha <!>”::您在InternalsVisibleToAttribute中指定的朋友程序集的名称必须完全与朋友程序集的名称相匹配,如下所示朋友的项目属性(在“应用程序”选项卡中)。

在我的情况下,我有一个项目Thingamajig和一个伴随项目ThingamajigAutoTests(名称已更改以保护有罪),这两个项目都生成了未签名的程序集。我正确地将属性[assembly: InternalsVisibleTo( "ThingamajigAutoTests" )]添加到Thingamajig \ AssemblyInfo.cs文件中,并注释掉了AssemblyKeyFileAssemblyKeyName属性,如上所述。 InternalsVisibleTo项目建设得很好,但其内部成员顽固地拒绝出现在自动测试项目中。

经过多次讨论后,我重新检查了<=>项目属性,发现程序集名称被指定为<!>“ThingamajigAutoTests.dll <!>”;。宾果 - 我添加了<!>“; .dll <!>”;扩展到<=>属性中的程序集名称,并且这些部分已经到位。

有时它是最小的东西......

如果您的程序集未签名,但仍然遇到相同的错误,请检查AssemblyInfo.cs文件中是否有以下任一行:

[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]

如果存在这些行中的任何一行(或两行),属性选项卡仍会将程序集显示为无符号,但InternalsVisibleTo属性将这些行的程序集视为强签名。只需删除(或注释掉)这些行,它就可以正常使用。

值得注意的是,如果<!>“朋友<!>”; (测试)程序集用C ++ / CLI编写,而不是C#/ VB.Net,然后你需要使用以下代码:

#using "AssemblyUnderTest.dll" as_friend

而不是项目引用或通常的#using语句。出于某种原因,在项目参考UI中无法做到这一点。

这是我用来快速生成此属性的宏。它有点hacky,但它的工作原理。在我的机器上。当最新签名的二进制文件在/bin/debug中时。 Etc模棱两可等等。无论如何,你可以看到它是如何获得密钥的,所以它会给你一个提示。随着时间的推移,修复/改进。

Sub GetInternalsVisibleToForCurrentProject()
    Dim temp = "[assembly:  global::System.Runtime.CompilerServices." + _
               "InternalsVisibleTo(""{0}, publickey={1}"")]"
    Dim projs As System.Array
    Dim proj As Project
    projs = DTE.ActiveSolutionProjects()
    If projs.Length < 1 Then
        Return
    End If

    proj = CType(projs.GetValue(0), EnvDTE.Project)
    Dim path, dir, filename As String
    path = proj.FullName
    dir = System.IO.Path.GetDirectoryName(path)
    filename = System.IO.Path.GetFileNameWithoutExtension(path)
    filename = System.IO.Path.ChangeExtension(filename, "dll")
    dir += "\bin\debug\"
    filename = System.IO.Path.Combine(dir, filename)
    If Not System.IO.File.Exists(filename) Then
        MsgBox("Cannot load file " + filename)
        Return
    End If
    Dim assy As System.Reflection.Assembly
    assy = System.Reflection.Assembly.Load(filename)
    Dim pk As Byte() = assy.GetName().GetPublicKey()
    Dim hex As String = BitConverter.ToString(pk).Replace("-", "")
    System.Windows.Forms.Clipboard.SetText(String.Format(temp, assy.GetName().Name, hex))
    MsgBox("InternalsVisibleTo attribute copied to the clipboard.")
End Sub

编译好友程序集(程序集)时,需要使用/ out:编译开关 不包含InternalsVisibleTo属性)。

编译器需要知道正在编译的程序集的名称,以确定生成的程序集是否应被视为友元程序集。

除了以上所有内容,当一切看起来都是正确的,但朋友组件固执地拒绝看到任何内部,重新加载解决方案或重新启动Visual Studio 可以解决问题。

在我使用VS.Net 2015的情况下,我需要签署 BOTH 程序集(如果至少要签署一个程序集,或者你想引用程序集的公钥)。

我的项目根本没有使用签名。所以我开始在我的测试库中添加一个符号键,并在我项目的基础库中使用InternalsVisibleTo-Attribute。但是VS.Net总是解释说它无法访问朋友的方法。

当我开始签署基础库(它可以是相同或另一个签名密钥 - 只要您对基础库进行签名)时,VS.Net立即能够按预期工作。

以前使用PublicKey的答案工作:( Visual Studio 2015:需要在一行,否则它会抱怨程序集引用无效或无法引用.PublicKeyToken没有用)

[assembly: InternalsVisibleTo("NameSpace.MyFriendAssembly, PublicKey=0024000004800000940000000602000000240000525341310004000001000100F73F4DDC11F0CA6209BC63EFCBBAC3DACB04B612E04FA07F01D919FB5A1579D20283DC12901C8B66A08FB8A9CB6A5E81989007B3AA43CD7442BED6D21F4D33FB590A46420FB75265C889D536A9519674440C3C2FB06C5924360243CACD4B641BE574C31A434CE845323395842FAAF106B234C2C1406E2F553073FF557D2DB6C5")]

感谢@Joe

获取好友程序集的公钥:

sn -Tp path\to\assembly\MyFriendAssembly.dll

在Developper命令提示符内(启动<!> gt;程序<!> gt; Visual Studio 2015 <!> gt; Visual Studio工具<!> gt; VS2015的开发人员命令提示符)。 感谢@Ian G。

尽管如此,在上面的内容之后,最后的触摸方式是让我签名我的朋友图书馆项目,就像签署图书馆的项目一样。由于它是一个新的测试库,它还没有签名。

您需要为程序集生成新的完整公钥,然后将该属性指定为程序集。

[assembly: InternalsVisibleTo("assemblyname,
PublicKey="Full Public Key")]

按照以下 MSDN 从visual studio为程序集生成新的完整公钥的步骤。

将“获取程序集公钥”项添加到“工具”菜单

在Visual Studio中,单击“工具”菜单上的外部工具

在“外部工具”对话框中,单击添加,然后在“标题”框中输入“获取程序集公钥”。

通过浏览到sn.exe来填充命令框。它通常安装在以下位置: C:\ Program Files(x86)\ Microsoft SDKs \ Windows \ v7.0a \ Bin \ x64 \ sn.exe

在“参数”框中,键入以下(区分大小写): -Tp $(TargetPath)。 选中“使用输出窗口”复选框。

点击确定。新命令将添加到“工具”菜单中。

每当您需要正在开发的程序集的公钥标记时,请单击“工具”菜单上的“获取程序集公钥”命令,并在“输出”窗口中显示公钥标记。

另一种可能难以追踪的可能性,具体取决于代码的编写方式。

  1. 您正在从另一个程序集Y
  2. 调用X中定义的内部方法
  3. 方法签名使用Z
  4. 中定义的内部类型
  5. 然后你必须在X和Z
  6. 中添加[InternalsVisibleTo]

    例如:

    // In X
    internal static class XType
    {
        internal static ZType GetZ() { ... }
    }
    
    // In Y:
    object someUntypedValue = XType.GetZ();
    
    // In Z:
    internal class ZType { ... }
    

    如果你有如上所述的内容,你不是直接在Y中引用ZType,在添加Y作为X的朋友之后,你可能会对你的代码仍然无法编译的原因感到困惑。

    在这种情况下,编译错误肯定会更有帮助。

仅当您希望将未签名的程序集保留为无符号程序集(并且由于多种原因而不想签名)时才适用:

还有一点:如果您将基础库从VS.Net编译到本地目录,它可能会按预期工作。

但是:只要将基本库编译为网络驱动器,就会应用安全策略,并且无法成功加载程序集。检查PublicKey匹配时,这会再次导致VS.NET或编译器失败。

最后,可以使用未签名的程序集: https://msdn.microsoft.com/en-us/library/bb384966.aspx 您必须确保BOTH程序集未签名 并且Assembly属性必须没有PublicKey信息:

<Assembly: InternalsVisibleTo("friend_unsigned_B")>

我是出于沮丧而写的。确保您授予访问权限的程序集按预期命名。

我重命名了我的项目,但这并不会自动更新程序集名称。右键单击您的项目,然后单击属性。在应用下,确保程序集名称默认名称空间符合您的预期。

我遇到了同样的问题。没有一个解决方案有效。

最终发现问题是由于X类明确地实现了接口Y,这是内部的。

方法X.InterfaceMethod不可用,但我不知道为什么。

解决方案是在测试库中强制转换(X作为YourInterface).InterfaceMethod,然后就可以了。

作为旁注,如果您想轻松获取公钥而不必使用sn并找出其选项,您可以下载方便的程序这里。它不仅确定了公钥,还创建了<!> quot; assembly:InternalsVisibleTo ... <!> quot;准备好将其复制到剪贴板并粘贴到您的代码中。

我刚用InternalsVisibleTo属性解决了类似的问题。一切似乎都是对的,我无法弄清楚为什么我瞄准的内部课程仍无法访问。

将键的大小写从大小写改为小写修复了问题。

如果您有多个引用的程序集 - 请检查所有必需的程序集是否具有InternalsVisibleTo属性。有时它并不明显,也没有消息说你必须将这个属性添加到一个程序集中。

1-签署测试项目:在Visual Studio中,通过选中测试项目签署程序集的属性窗口带有相同短语的复选框,位于签名标签中。

2-为测试项目创建一个PublicKey:打开Visual Studio命令提示符(例如VS 2017的开发人员命令提示符)。转到测试项目的.dll文件所在的文件夹。通过sn.exe创建公钥:

sn -Tp TestProject.dll

请注意,参数是-Tp,但不是-tp。

3-将PublicKey引入要测试的项目:转到要测试的项目中的AssemblyInfo.cs文件,并添加此行并创建PublicKey在上一步中:

[组件:InternalsVisibleTo(<!>; <!> QUOT的 TestProjectAssemblyName 下,的公钥 = 2066212d128683a85f31645c60719617ba512c0bfdba6791612ed56350368f6cc40a17b4942ff16cda9e760684658fa3f357c137a1005b04cb002400000480000094000000060200000024000052534131000400000100010065fe67a14eb30ffcdd99880e9d725f04e5c720dffc561b23e2953c34db8b7c5d4643f476408ad1b1e28d6bde7d64279b0f51bf0e60be2d383a6c497bf27307447506b746bd2075 QUOT)]

不要忘记将上述PublicKey替换为您的。

4-将私有方法设为内部:在要测试的项目中,将方法的访问修饰符更改为内部。

内部静态 void DoSomething(){...}

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top