2008-09-20 114 views
62

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

“MyClassName”不可访问由于

两个组件都签署了保护水平,我在属性声明中列出的正确的密钥。有任何想法吗?

+1

你可以发布你想要暴露的InternalsVisibleTo属性吗?没有看到你在看什么,很难说出了什么问题。 – 2008-09-20 03:04:58

回答

86

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

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

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

+45

要获取MSDN文档的朋友大会“sn -Tp MyFriendAssembly” – 2009-07-06 09:54:36

+27

-1000的公钥,此文档仍然不完整。 – Will 2009-11-23 16:37:31

+0

很好,所以我怎么得到那^键? – DevDave 2012-02-06 17:33:11

4

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

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

+0

默认情况下,如果.msbuild文件包含以下行,则Microsoft C#目标将添加`/ out`选项: YourFriendAssemblyName`。这也可以在项目的属性中的“应用程序”选项卡的“程序集名称”字段中进行设置。 – 2013-05-21 17:15:28

+0

宾果,这也是我的问题。谢谢5年后! – LLL 2013-11-25 23:33:33

10

值得一noteing,如果“朋友”(测试)组装它是用C++/CLI,而不是C#/ VB.Net,那么你需要使用以下命令:

#using "AssemblyUnderTest.dll" as_friend 

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

科林

35

如果您的组件没有签名,但您仍然得到同样的错误,请检查您的AssemblyInfo.cs文件进行以下任一线路:

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

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

5

下面是我用来快速生成此属性的宏。它有点哈克,但它的作品。在我的机器上。当最新的带符号二进制数在/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 
0

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

0

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

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

35

另一种可能的“疑难杂症”:您在InternalsVisibleToAttribute必须精确指定如图所示朋友的项目属性(在应用程序选项卡)符合您的朋友组装的名字朋友集的名称。

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

经过多次头部刮擦,我重新检查了ThingamajigAutoTests项目属性,并发现程序集名称被指定为“ThingamajigAutoTests.dll”。 Bingo - 我在InternalsVisibleTo属性中的程序集名称中添加了“.dll”扩展名,并且这些部分落入了原位。

有时它是微不足道的事情......

3

除了上述所有,当一切似乎是正确的,但朋友组装顽固地拒绝看到任何内部,重装解决方案或重新启动Visual Studio中可以解决问题。

2

以公钥以前的答案的工作:(Visual Studio的2015年:必须在同一行,否则就抱怨说,装配基准无效或不能引用的公钥不工作)

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

感谢@Joe

为了让朋友组装的公钥:

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

里面一个Developper命令提示符(启动>程序>的Visual Studio 2015年> Visual Studio工具>开发人员命令提示符VS2015)。 感谢@Ian G.

尽管上面提到的最后一个接触让我对我的朋友库项目签名的方式与图书馆共享项目签署的方式一样。由于它是一个新的测试库,它尚未签名。

2

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

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

按照下面的MSDN步骤来为从Visual Studio装配新的完整的公钥。

于获取大会公钥项目添加到工具菜单

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

在外部工具对话框中,单击添加并在标题框中输入Get Assembly Public Key。

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

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

Click OK。新的命令被添加到工具菜单中。

无论何时需要您正在开发的程序集的公钥令牌,请单击工具菜单上的获取程序集公用密钥命令,公用密钥令牌出现在输出窗口中。

3

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

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

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

1

仅适用,如果你想保持无符号组件为无符号组件(和不愿签字的几个原因):

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

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

最后,它可以使用无符号的组件: https://msdn.microsoft.com/en-us/library/bb384966.aspx 您必须确保两个组件都没有签署 和大会属性必须是不公钥信息:

<Assembly: InternalsVisibleTo("friend_unsigned_B")>

0

另一种可能性,可能是很难跟踪,这取决于你的代码是如何写入的。

  1. 你调用从另一个组件中X Y的定义
  2. 一个内部方法的方法,签名使用Z中定义的内部类型
  3. 你就必须添加[InternalsVisibleTo]在X AND Z中

例如:

// In X 
internal static class XType 
{ 
    internal static ZType GetZ() { ... } 
} 

// In Y: 
object someUntypedValue = XType.GetZ(); 

// In Z: 
internal class ZType { ... } 

如果您有它这样写上面,在那里你不是指ŧ o直接在Y中使用ZType,在将Y添加为X的朋友后,您可能会疑惑为什么您的代码仍然无法编译。

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

0

我正在写这个出来的挫折。确保您授予访问权限的程序集按照您的预期命名。

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