InternalsVisibleTo 属性が機能しない
-
01-07-2019 - |
質問
を使用しようとしています InternalsVisibleTo
Assembly 属性を使用して、.NET クラス ライブラリの内部クラスを単体テスト プロジェクトに表示できるようにします。何らかの理由で、次のようなエラー メッセージが表示され続けます。
「MyClassName」は保護レベルのためアクセスできません
どちらのアセンブリも署名されており、属性宣言に正しいキーがリストされています。何か案は?
解決
属性に正しい公開キーが指定されていると確信していますか?公開鍵トークンだけでなく、完全な公開鍵を指定する必要があることに注意してください。それは次のようになります:
[assembly: InternalsVisibleTo("MyFriendAssembly,
PublicKey=0024000004800000940000000602000000240000525341310004000001000100F73
F4DDC11F0CA6209BC63EFCBBAC3DACB04B612E04FA07F01D919FB5A1579D20283DC12901C8B66
A08FB8A9CB6A5E81989007B3AA43CD7442BED6D21F4D33FB590A46420FB75265C889D536A9519
674440C3C2FB06C5924360243CACD4B641BE574C31A434CE845323395842FAAF106B234C2C140
6E2F553073FF557D2DB6C5")]
それは 320 程度の 16 進数です。なぜ完全な公開キーを指定する必要があるのかわかりません。おそらく、他のアセンブリ参照で使用されている公開キー トークンだけを使用すると、誰かがフレンド アセンブリの ID を偽装するのが簡単になるでしょう。
他のヒント
もう一つ考えられる「落とし穴」:で指定したフレンド アセンブリの名前。 InternalsVisibleToAttribute
しなければならない その通り フレンドのプロジェクト プロパティ ([アプリケーション] タブ内) に表示されるフレンド アセンブリの名前と一致します。
私の場合、プロジェクトがありました Thingamajig
そしてそれに付随するプロジェクト ThingamajigAutoTests
(有罪者を保護するために名前は変更されました)どちらも署名のない集会を開催しました。属性を正式に追加しました [assembly: InternalsVisibleTo( "ThingamajigAutoTests" )]
Thingamajig\AssemblyInfo.cs ファイルに追加し、コメントアウトしました。 AssemblyKeyFile
そして AssemblyKeyName
属性は上記のとおりです。の Thingamajig
プロジェクトは問題なく構築されましたが、内部メンバーは自動テスト プロジェクトに参加することを頑なに拒否しました。
頭を悩ませた後、再確認しました ThingamajigAutoTests
プロジェクトのプロパティを確認すると、アセンブリ名が「ThingamajigAutoTests.dll」として指定されていることがわかりました。ビンゴ - アセンブリ名に「.dll」拡張子を追加しました。 InternalsVisibleTo
属性が決まり、ピースが所定の位置に収まりました。
時には些細な事でも…
アセンブリが署名されていないのに同じエラーが発生する場合は、AssemblyInfo.cs ファイルに次のいずれかの行がないか確認してください。
[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]
これらの行のいずれか (または両方) が存在する場合、プロパティ タブにはアセンブリが未署名として表示されますが、InternalsVisibleTo 属性はこれらの行を含むアセンブリを強力に署名されたものとして扱います。これらの行を削除 (またはコメントアウト) するだけで、問題なく動作するはずです。
「フレンド」(テスト) アセンブリが C#/VB.Net ではなく C++/CLI で記述されている場合は、次のものを使用する必要があることに注意してください。
#using "AssemblyUnderTest.dll" as_friend
プロジェクトリファレンスや通常の代わりに #using
声明。何らかの理由で、プロジェクト参照 UI ではこれを行う方法がありません。
使用できます AssemblyHelper ツール これにより、InternalsVisibleTo 構文が生成されます。こちらです 最新バージョンへのリンク. 。これは厳密な名前のアセンブリに対してのみ機能することに注意してください。
この属性をすばやく生成するために使用するマクロを次に示します。ちょっとハック的ですが、うまくいきます。私のマシンでは。最新の署名付きバイナリが存在する場合 /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
/out を使用する必要があります。コンパイラスイッチフレンドアセンブリ(InternalsVisibleto属性を含まないアセンブリ)をコンパイルするとき。
コンパイラは、結果のアセンブリをフレンド アセンブリと見なすべきかどうかを判断するために、コンパイル中のアセンブリの名前を知る必要があります。
上記のすべてに加えて、すべてが正しいように見えても、友人の集会が頑なに内部を見ることを拒否した場合、 ソリューションをリロードするか、Visual Studio を再起動する 問題を解決できます。
私の場合、VS.Net 2015 を使用した場合、署名する必要がありました。 両方 アセンブリ (少なくとも 1 つのアセンブリに署名する必要がある場合、またはアセンブリの公開キーを参照したい場合)。
私のプロジェクトでは署名をまったく使用しませんでした。そこで、テスト ライブラリに署名キーを追加し、プロジェクトのベース ライブラリで InternalsVisibleTo-Attribute を使用し始めました。しかし、VS.Net は常に、friend メソッドにアクセスできないと説明していました。
基本ライブラリに署名し始めると (基本ライブラリに署名する限り、同じ署名キーでも別の署名キーでも構いません)、VS.Net はすぐに期待どおりに動作するようになりました。
PublicKey を使用した以前の回答は機能しました:(Visual Studio 2015:1 行に記述する必要があります。そうしないと、アセンブリ参照が無効であるか、参照できないというメッセージが表示されます。PublicKeyToken が機能しませんでした)
[assembly: InternalsVisibleTo("NameSpace.MyFriendAssembly, PublicKey=0024000004800000940000000602000000240000525341310004000001000100F73F4DDC11F0CA6209BC63EFCBBAC3DACB04B612E04FA07F01D919FB5A1579D20283DC12901C8B66A08FB8A9CB6A5E81989007B3AA43CD7442BED6D21F4D33FB590A46420FB75265C889D536A9519674440C3C2FB06C5924360243CACD4B641BE574C31A434CE845323395842FAAF106B234C2C1406E2F553073FF557D2DB6C5")]
@ジョーに感謝します
フレンド アセンブリの公開キーを取得するには:
sn -Tp path\to\assembly\MyFriendAssembly.dll
開発者コマンド プロンプト内 ([スタートアップ] > [プログラム] > [Visual Studio 2015] > [Visual Studio ツール] > [VS2015 の開発者コマンド プロンプト])。@Ian G に感謝します。
ただし、上記の後に私にとってうまく機能する最後の仕上げは、共有するライブラリのプロジェクトに署名するのと同じ方法で、友人のライブラリ プロジェクトに署名することでした。新しい Test ライブラリだったので、まだ署名されていませんでした。
アセンブリの新しい完全な公開キーを生成し、アセンブリに属性を指定する必要があります。
[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.
[引数] ボックスに次のように入力します (大文字と小文字は区別されます)。 -Tp $(ターゲットパス)。[出力ウィンドウを使用する] チェック ボックスをオンにします。
クリック わかりました. 。新しいコマンドが [ツール] メニューに追加されます。
開発中のアセンブリの公開キー トークンが必要な場合は、[ツール] メニューの [アセンブリ公開キーの取得] コマンドをクリックすると、公開キー トークンが出力ウィンドウに表示されます。
コードの記述方法によっては、追跡が難しい可能性があるもう 1 つの可能性があります。
- X で定義された内部メソッドを別のアセンブリ Y から呼び出しています。
- メソッド シグネチャは、Z で定義された内部型を使用します。
- 次に、[InternalsVisibleTo] を X と 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 のフレンドとして追加した後、なぜコードがコンパイルできないのか不思議に思うかもしれません。
この場合、コンパイル エラーの方が確実に役立つ可能性があります。
未署名のアセンブリを未署名のアセンブリとして保持したい場合 (およびいくつかの理由で署名したくない場合) にのみ適用されます。
さらにもう 1 つのポイントがあります。基本ライブラリを VS.Net からローカル ディレクトリにコンパイルすると、期待どおりに動作する可能性があります。
しかし:基本ライブラリをネットワーク ドライブにコンパイルするとすぐに、セキュリティ ポリシーが適用され、アセンブリを正常に読み込むことができなくなります。これにより、PublicKey の一致をチェックするときに、VS.NET またはコンパイラが再び失敗します。
最後に、署名のないアセンブリを使用できるようになります。https://msdn.microsoft.com/en-us/library/bb384966.aspx両方のアセンブリに署名されておらず、アセンブリ属性がpublicKey情報がないことを確認する必要があります。
<Assembly: InternalsVisibleTo("friend_unsigned_B")>
イライラしてこれを書いています。アクセスを許可するアセンブリに期待どおりの名前が付いていることを確認してください。
プロジェクトの名前を変更しましたが、アセンブリ名は自動的に更新されません。プロジェクトを右クリックし、 プロパティ. 。下 応用, を確認してください。 アセンブリ名 そして デフォルトの名前空間 あなたが期待しているものです。
私も同じ問題を抱えていました。どの解決策も機能しませんでした。
最終的に、この問題はクラス X が内部インターフェイス Y を明示的に実装していることが原因であることが判明しました。
メソッド X.InterfaceMethod は利用できませんでしたが、理由はわかりません。
解決策は、テスト ライブラリで (X as YourInterface).InterfaceMethod をキャストすることで、うまくいきました。
補足として、sn を使用せずに公開キーを簡単に取得し、そのオプションを理解したい場合は、便利なプログラムをダウンロードできます。 ここ. 。公開キーを決定するだけでなく、「アセンブリ」も作成します。InternalsVisibleTo...」行をクリップボードにコピーしてコードに貼り付ける準備ができています。
同様の問題を解決したばかりです InternalsVisibleTo
属性。すべてが正しいように見えましたが、私が目指していた内部クラスにまだアクセスできない理由がわかりませんでした。
キーの大文字と小文字を大文字から小文字に変更すると、問題が解決されました。
参照されているアセンブリが複数ある場合は、必要なすべてのアセンブリに InternalsVisibleTo 属性があることを確認してください。この属性を他のアセンブリに追加する必要があることが明らかではなく、メッセージも表示されない場合があります。
1- テスト プロジェクトに署名します。 Visual Studio で、プロパティ ウィンドウに移動します。 テストプロジェクト そして 議会に署名する 同じ語句のチェックボックスをオンにすると、 署名 タブ。
2- テスト プロジェクトの公開キーを作成します。 Visual Studio コマンド プロンプトを開きます (例:VS 2017 の開発者コマンド プロンプト)。の .dll ファイルが保存されているフォルダーに移動します。 テストプロジェクト 存在します。sn.exe を使用して公開キーを作成します。
sn -Tp テストプロジェクト.dll
引数は -Tp ですが、-tp ではないことに注意してください。
3- テストするプロジェクトに PublicKey を導入します。 AssemblyInfo.cs ファイルに移動します。 テストされるプロジェクト そして、前の手順で作成した PublicKey を含む次の行を追加します。
[組み立て:InternalsVisibleTo("テストプロジェクトアセンブリ名, 公開鍵=2066212d128683a85f31645c60719617ba512c0bfdba6791612ed56350368f6cc40a17b4942ff16cda9e760684658fa3f357c137a1005b04cb002400000480000094 000000060200000024000052534131000400000100010065fe67a14eb30ffcdd99880e9d725f04e5c720dffc561b23e2953c34db8b7c5d4643f476408ad1b1e28d6bde 7d64279b0f51bf0e60be2d383a6c497bf27307447506b746bd2075")]
上記の PublicKey を自分のものに置き換えることを忘れないでください。
4- プライベート メソッドを内部にします。 テストするプロジェクトで、メソッドのアクセス修飾子をinternal に変更します。
内部静電気 void DoSomething(){...}