InternalsVisibleTo属性不起作用

我正在尝试使用InternalsVisibleTo程序集属性来使我的unit testing项目中的.NET类库中的内部类可见。 出于某种原因,我不断收到一条错误消息,说:

由于其保护级别,“MyClassName”无法访问

这两个程序集都已签名,并且在属性声明中列出了正确的键。 有任何想法吗?

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

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

这是320左右的hex数字。 不知道为什么你需要指定完整的公钥 – 可能只有在其他程序集引用中使用的公钥标记,对于某人来说,欺骗朋友程序集的身份将更容易。

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

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

属性选项卡仍然显示您的程序集为无符号(如果这两行中的任何一行存在),但InternalsVisibleTo属性将这些行视为强签名。 简单地删除(或注释掉)这些行,它应该适合你。

另一个可能的“陷阱”:在InternalsVisibleToAttribute指定的朋友程序集的名称必须与朋友程序集的名称(在“应用程序”选项卡中) 完全匹配。

在我的情况下,我有一个项目Thingamajig和一个同伴项目ThingamajigAutoTests (名称改变,以保护有罪),都产生未签名的程序集。 我正确地将属性[assembly: InternalsVisibleTo( "ThingamajigAutoTests" )]到Thingamajig \ AssemblyInfo.cs文件中,并注释掉上面提到的AssemblyKeyFileAssemblyKeyName属性。 Thingamajig项目build成不错,但内部成员固执地拒绝在自动testing项目中出现。

经过多次的搔抓,我重新检查了ThingamajigAutoTests项目属性,发现程序集名称被指定为“ThingamajigAutoTests.dll”。 宾果 – 我在InternalsVisibleTo属性中的程序集名称中添加了“.dll”扩展名,并且这些作品落入了原位。

有时候这是最小的事

值得注意的是,如果“朋友”(testing)程序集是用C ++ / CLI编写的,而不是C#/ VB.Net,则需要使用以下代码:

 #using "AssemblyUnderTest.dll" as_friend 

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

科林

您可以使用AssemblyHelper工具来为您生成InternalsVisibleTo语法。 这里是最新版本的链接 。 请注意,它只适用于强名称的程序集。

这是一个我用来快速生成这个属性的macros。 它有点哈克,但它的作品。 在我的机器上。 当最新的签名二进制文件位于/bin/debug 。 等等等等。总之,你可以看到它是如何获得关键的,所以这会给你一个提示。 随时间改变,修复/改善

 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 

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

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

除了上述所有内容之外,当一切似乎都是正确的,但是这个朋友程序集固执地拒绝看到任何内部消息时, 重新加载解决scheme或重新启动Visual Studio可以解决问题。

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

我的项目根本没有使用签名。 所以我开始为我的testing库添加一个符号键,并在我的项目的基础库中使用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 

在开发者命令提示符下(启动>程序> Visual Studio 2015> Visual Studio工具>开发人员命令提示符VS2015)。 感谢@Ian G.

尽pipe如此,最终让我在上面工作的最后一步是签署我的朋友图书馆项目,就像签署图书馆的项目一样。 由于它是一个新的testing库,它还没有被签名。

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

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

按照下面的MSDN步骤来从Visual Studio生成新的完整的公钥。

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

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

在外部工具对话框中,单击添加并在标题框中input获取组件公钥。

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

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

点击OK 。 新的命令被添加到工具菜单。

只要您需要您正在开发的程序集的公钥标记,请单击“工具”菜单上的“获取程序集公用密钥”命令,公用密钥标记将出现在“输出”窗口中。

仅在您将未签名的程序集保存为无符号程序集(并且由于以下原因不想对其进行签名)时才适用:

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

但是:一旦你编译你的基础库到networking驱动器,安全策略适用,程序集不能成功加载。 这再次导致VS.NET或编译器在检查PublicKey匹配时失败。

最后,可以使用未签名的程序集: https : //msdn.microsoft.com/en-us/library/bb384966.aspx您必须确保两个程序集都没有签名而程序集属性必须没有公钥信息:

<Assembly: InternalsVisibleTo("friend_unsigned_B")>

作为一个方面说明,如果你想轻松得到公钥而不必使用sn并找出它的选项,你可以在这里下载这个方便的程序。 它不仅确定了公钥,而且还创build了“assembly:InternalsVisibleTo …”行,准备将其复制到剪贴板并粘贴到您的代码中。

我只是用InternalsVisibleTo Attribute解决了一个类似的问题。 一切似乎都对,我无法弄清楚为什么我所瞄准的内部class级仍然无法访问。

将密钥的大小写从大写更改为小写解决了问题。

另一个可能是棘手的追查可能性,这取决于你的代码是如何写的。

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

例如:

 // 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的朋友之后,你可能会感到困惑,为什么你的代码仍然不能编译。

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

我是从挫折中写出来的。 确保您授予访问权限的程序集按照您的预期命名。

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