我正在尝试使用InternalsVisibleTo
程序集属性来使.NET类库中的内部类对我的单元测试项目可见。出于某种原因,我不断收到一条错误消息:
'MyClassName'由于其保护级别而无法访问
两个程序集都已签名,并且我在属性声明中列出了正确的密钥。有什么想法吗?
答案 0 :(得分:95)
您是否完全确定属性中指定了正确的公钥? 请注意,您需要指定完整的公钥,而不仅仅是公钥标记。它看起来像:
[assembly: InternalsVisibleTo("MyFriendAssembly,
PublicKey=0024000004800000940000000602000000240000525341310004000001000100F73
F4DDC11F0CA6209BC63EFCBBAC3DACB04B612E04FA07F01D919FB5A1579D20283DC12901C8B66
A08FB8A9CB6A5E81989007B3AA43CD7442BED6D21F4D33FB590A46420FB75265C889D536A9519
674440C3C2FB06C5924360243CACD4B641BE574C31A434CE845323395842FAAF106B234C2C140
6E2F553073FF557D2DB6C5")]
它是320左右的十六进制数字。不确定为什么需要指定完整的公钥 - 可能只使用其他程序集引用中使用的公钥标记,这样可以更容易欺骗朋友程序集的身份。
答案 1 :(得分:39)
另一种可能的“问题”:您在InternalsVisibleToAttribute
中指定的朋友程序集的名称必须完全与朋友程序集的名称相匹配,如朋友的项目属性中所示(在“应用程序”选项卡)。
就我而言,我有一个项目Thingamajig
和一个伴侣项目ThingamajigAutoTests
(名称已更改以保护有罪),这两个项目都生成了未签名的程序集。我正确地将属性[assembly: InternalsVisibleTo( "ThingamajigAutoTests" )]
添加到Thingamajig \ AssemblyInfo.cs文件中,并注释掉了AssemblyKeyFile
和AssemblyKeyName
属性,如上所述。 Thingamajig
项目建设得很好,但其内部成员顽固地拒绝出现在自动测试项目中。
经过多次讨论后,我重新检查了ThingamajigAutoTests
项目属性,发现程序集名称被指定为“ThingamajigAutoTests.dll”。宾果游戏 - 我在InternalsVisibleTo
属性中为程序集名称添加了“.dll”扩展名,并且这些文章已经落实到位。
有时它是最小的东西......
答案 2 :(得分:35)
如果您的程序集未签名,但仍然遇到相同的错误,请检查AssemblyInfo.cs文件中是否有以下任一行:
[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]
如果存在这些行中的任何一行(或两行),属性选项卡仍会将程序集显示为无符号,但InternalsVisibleTo属性将这些行的程序集视为强签名。只需删除(或注释掉)这些行,它就可以正常使用。
答案 3 :(得分:11)
值得注意的是,如果“朋友”(测试)程序集是用C ++ / CLI而不是C#/ VB.Net编写的,那么你需要使用以下内容:
#using "AssemblyUnderTest.dll" as_friend
而不是项目引用或通常的#using
语句。出于某种原因,在项目参考UI中无法做到这一点。
答案 4 :(得分:9)
您可以使用AssemblyHelper tool为您生成InternalsVisibleTo语法。这是the link to the latest version。请注意,它仅适用于强名称的程序集。
答案 5 :(得分:5)
这是我用来快速生成此属性的宏。它有点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
答案 6 :(得分:4)
编译好友程序集(程序集)时,需要使用/ out:编译开关 不包含InternalsVisibleTo属性)。
编译器需要知道正在编译的程序集的名称,以确定生成的程序集是否应被视为友元程序集。
答案 7 :(得分:3)
除了以上所有内容,当一切看起来都是正确的,但朋友组件固执地拒绝看到任何内部,重新加载解决方案或重新启动Visual Studio 可以解决问题。
答案 8 :(得分:3)
在我使用VS.Net 2015的情况下,我需要签署 BOTH 程序集(如果至少要签署一个程序集,或者你想引用程序集的公钥)。
我的项目根本没有使用签名。所以我开始在我的测试库中添加一个符号键,并在我项目的基础库中使用InternalsVisibleTo-Attribute。但是VS.Net总是解释说它无法访问朋友的方法。
当我开始签署基础库(它可以是相同或另一个签名密钥 - 只要您对基础库进行签名)时,VS.Net立即能够按预期工作。
答案 9 :(得分:2)
以前使用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。
尽管如此,在上面的内容之后,最后的触摸方式是让我签名我的朋友图书馆项目,就像签署图书馆的项目一样。由于它是一个新的测试库,它还没有签名。
答案 10 :(得分:2)
您需要为程序集生成新的完整公钥,然后将该属性指定为程序集。
[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)。 选中“使用输出窗口”复选框。
点击确定。新命令将添加到“工具”菜单中。
每当您需要正在开发的程序集的公钥标记时,请单击“工具”菜单上的“获取程序集公钥”命令,并在“输出”窗口中显示公钥标记。
答案 11 :(得分:2)
另一种可能难以追踪的可能性,具体取决于代码的编写方式。
例如:
// 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的朋友之后,你可能会对你的代码仍然无法编译的原因感到困惑。
在这种情况下,编译错误肯定会更有帮助。
答案 12 :(得分:1)
仅当您希望将未签名的程序集保留为未签名的程序集(并且由于多种原因而不想签名)时才适用:
还有一点:如果您将基础库从VS.Net编译到本地目录,它可能会按预期工作。
但是:只要将基本库编译为网络驱动器,就会应用安全策略,并且无法成功加载程序集。检查PublicKey匹配时,这会再次导致VS.NET或编译器失败。
最后,可以使用未签名的程序集: https://msdn.microsoft.com/en-us/library/bb384966.aspx 您必须确保BOTH程序集未签名 并且Assembly属性必须没有PublicKey信息:
<Assembly: InternalsVisibleTo("friend_unsigned_B")>
答案 13 :(得分:1)
我是出于沮丧而写的。确保您授予访问权限的程序集按预期命名。
我重命名了我的项目,但这并不会自动更新程序集名称。右键单击您的项目,然后单击属性。在应用程序下,确保程序集名称和默认名称空间符合您的预期。
答案 14 :(得分:1)
我遇到了同样的问题。没有一个解决方案有效。
最终发现问题是由于X类明确地实现了接口Y,这是内部的。
方法X.InterfaceMethod不可用,但我不知道为什么。
解决方案是在测试库中强制转换(X作为YourInterface).InterfaceMethod,然后就可以了。
答案 15 :(得分:0)
我刚刚解决了InternalsVisibleTo
属性的类似问题。一切似乎都是正确的,我无法弄清楚为什么我瞄准的内部课程仍然无法访问。
将键的大小写从大小写改为小写修复了问题。
答案 16 :(得分:0)
作为旁注,如果您想轻松获取公钥而不必使用sn并找出其选项,您可以下载方便的程序here。它不仅可以确定公钥,还可以创建“assembly:InternalsVisibleTo ...”行,可以将其复制到剪贴板并粘贴到代码中。
答案 17 :(得分:0)
如果您有多个引用的程序集 - 请检查所有必需的程序集是否具有InternalsVisibleTo属性。有时它并不明显,也没有消息说你必须将这个属性添加到一个程序集中。
答案 18 :(得分:0)
1-签名测试项目::在Visual Studio中,转到测试项目的属性窗口,然后通过选中签名标签中具有相同短语的复选框。
2-为测试项目创建一个公钥::打开Visual Studio命令提示符(例如VS 2017的开发人员命令提示符)。转到测试项目的.dll文件所在的文件夹。通过sn.exe创建公共密钥:
sn -Tp TestProject.dll
请注意,参数是-Tp,而不是-tp。
3-将PublicKey引入要测试的项目::转到要测试的项目中的AssemblyInfo.cs文件,并将此行与创建的PublicKey添加在一起在上一步中:
[组件:InternalsVisibleTo( “<强> TestProjectAssemblyName 下,的公钥强> = 2066212d128683a85f31645c60719617ba512c0bfdba6791612ed56350368f6cc40a17b4942ff16cda9e760684658fa3f357c137a1005b04cb002400000480000094000000060200000024000052534131000400000100010065fe67a14eb30ffcdd99880e9d725f04e5c720dffc561b23e2953c34db8b7c5d4643f476408ad1b1e28d6bde7d64279b0f51bf0e60be2d383a6c497bf27307447506b746bd2075”)]
别忘了用您的公钥替换上面的公钥。
4-将私有方法设置为内部方法:在要测试的项目中,将方法的访问修饰符更改为内部方法。
内部静态无效DoSomething(){...}