it-swarm.com.de

Das InternalsVisibleTo-Attribut funktioniert nicht

Ich versuche, das Assembly-Attribut InternalsVisibleTo zu verwenden, um meine internen Klassen in einer .NET-Klassenbibliothek für mein Komponententestprojekt sichtbar zu machen. Aus irgendeinem Grund bekomme ich immer eine Fehlermeldung, die besagt:

"MyClassName" ist aufgrund seines Schutzniveaus nicht zugänglich

Beide Assemblys sind signiert und ich habe den richtigen Schlüssel in der Attributdeklaration aufgeführt. Irgendwelche Ideen?

68
skb

Sind Sie absolut sicher, dass Sie den richtigen öffentlichen Schlüssel im Attribut angegeben haben? Beachten Sie, dass Sie den vollständigen öffentlichen Schlüssel angeben müssen, nicht nur das Token des öffentlichen Schlüssels. Es sieht ungefähr so ​​aus:

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

Es sind etwa 320 Hex-Ziffern. Sie sind sich nicht sicher, warum Sie den vollständigen öffentlichen Schlüssel angeben müssen - möglicherweise nur mit dem öffentlichen Schlüssel-Token, das in anderen Assembly-Referenzen verwendet wird. Es wäre für jemanden einfacher, die Identität der Freunde Assembly zu fälschen.

91
Joe

Ein anderes mögliches "gotcha": Der Name der Friend-Assembly, die Sie in der Variablen InternalsVisibleToAttribute angeben, muss genau mit dem Namen Ihrer Friend-Assembly übereinstimmen, wie in den Projekteigenschaften des Freundes (auf der Registerkarte Anwendung) angegeben.

In meinem Fall hatte ich ein Projekt Thingamajig und ein Begleitprojekt ThingamajigAutoTests (Namen geändert, um die Schuldigen zu schützen), die beide unsignierte Assemblies produzierten. Ich habe der Datei Thingamajig\AssemblyInfo.cs das Attribut [Assembly: InternalsVisibleTo( "ThingamajigAutoTests" )] hinzugefügt und die Attribute AssemblyKeyFile und AssemblyKeyName auskommentiert, wie oben angegeben. Das Thingamajig-Projekt war gut gebaut, aber seine internen Mitglieder weigerten sich hartnäckig, im Autotest-Projekt zu erscheinen.

Nach vielem Kopfkratzen überprüfte ich die ThingamajigAutoTests-Projekteigenschaften und stellte fest, dass der Assemblyname als "ThingamajigAutoTests.dll" angegeben wurde. Bingo - Ich habe die Erweiterung ".dll" zum Assemblynamen im InternalsVisibleTo-Attribut hinzugefügt, und die Teile wurden zusammengefügt.

Manchmal sind es die kleinsten Dinge ...

39
John Beyer

Wenn Ihre Assemblys nicht signiert sind, Sie jedoch immer noch den gleichen Fehler erhalten, überprüfen Sie Ihre AssemblyInfo.cs-Datei auf eine der folgenden Zeilen:

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

Auf der Registerkarte "Eigenschaften" wird Ihre Assembly weiterhin als unsigniert angezeigt, wenn eine oder beide dieser Zeilen vorhanden sind. Das Attribut "InternalsVisibleTo" behandelt jedoch eine Assembly mit diesen Zeilen als stark signiert. Löschen Sie diese Zeilen einfach (oder kommentieren Sie sie aus), und es sollte für Sie funktionieren.

35
Skimedic

Es ist erwähnenswert, dass, wenn die Assembly "friend" (testet) in C++/CLI und nicht in C #/VB.Net geschrieben ist, Folgendes verwendet werden muss:

#using "AssemblyUnderTest.dll" as_friend

anstelle einer Projektreferenz oder der üblichen #using-Anweisung. Aus irgendeinem Grund ist dies in der Projektreferenz-Benutzeroberfläche nicht möglich.

11
Colin Desmond

Sie können das AssemblyHelper-Tool verwenden, das die InternalsVisibleTo-Syntax für Sie generiert. Hier ist der Link zur neuesten Version . Beachten Sie, dass dies nur für Assemblys mit starkem Namen funktioniert.

9
Vadim

Hier ist ein Makro, mit dem ich dieses Attribut schnell generieren kann. Es ist ein bisschen hackig, aber es funktioniert. Auf meiner Maschine Wenn sich die letzte signierte Binärdatei in /bin/debug befindet. Etwas Äquivokation usw. Jedenfalls können Sie sehen, wie der Schlüssel abgerufen wird, so dass Sie einen Hinweis erhalten. Fix/verbessern, wie es Ihre Zeit erlaubt.

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
5
Will

Sie müssen den Compiler-Schalter/out: beim Kompilieren der Friend-Assembly verwenden (die Assembly, die Das Attribut InternalsVisibleTo nicht enthält). 

Der Compiler muss den Namen der Assembly kennen, die kompiliert wird, um zu bestimmen, ob die resultierende Assembly als eine Friend Assembly betrachtet werden soll. 

4
Ash

Zusätzlich zu all dem oben genannten, wenn alles richtig zu sein scheint, aber die befreundete Assembly hartnäckig keine Einbauten sieht, die Lösung neu laden oder Visual Studio neu starten kann das Problem lösen.

3
Alex J

In meinem Fall mit VS.Net 2015 musste ich BEIDE Assemblys signieren (wenn mindestens eine Assembly unterzeichnet werden soll oder Sie auf den öffentlichen Schlüssel Ihrer Assembly verweisen möchten).

Bei meinem Projekt wurde überhaupt nicht signiert. Also fing ich an, einen Zeichenschlüssel zu meiner Testbibliothek hinzuzufügen und das InternalsVisibleTo-Attribut in der Basisbibliothek meines Projekts zu verwenden. VS.Net erklärte jedoch immer, dass es keinen Zugriff auf die Friend-Methoden gab.

Als ich mit dem Signieren der Basisbibliothek begann (dies kann derselbe oder ein anderer Signierschlüssel sein - solange Sie die Basisbibliothek signieren), konnte VS.Net sofort wie erwartet arbeiten.

3
Jochen

Je nachdem, wie Ihr Code geschrieben wird, kann es schwierig sein, eine andere Möglichkeit zu finden.

  1. Sie rufen eine in X definierte interne Methode einer anderen Assembly Y auf
  2. Die Methodensignatur verwendet interne Typen, die in Z definiert sind
  3. Sie müssen dann [InternalsVisibleTo] in X AND in Z hinzufügen

Zum Beispiel:

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

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

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

Wenn Sie es wie oben geschrieben haben und sich nicht direkt auf ZType in Y beziehen, nachdem Sie Y als Freund von X hinzugefügt haben, werden Sie vielleicht verwirrt, warum Ihr Code immer noch nicht kompiliert wird.

Der Kompilierungsfehler könnte in diesem Fall definitiv hilfreicher sein.

2
Tatiana Racheva

Sie müssen einen neuen öffentlichen Schlüssel für die Assembly generieren und dann das Attribut für Assembly angeben.

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

Führen Sie die folgenden Schritte aus: MSDN , um einen neuen öffentlichen Schlüssel für die Assembly von Visual Studio zu generieren.

So fügen Sie dem Menü "Extras" einen öffentlichen Baugruppen-Get-Assembly-Eintrag hinzu

Klicken Sie in Visual Studio im Menü Extras auf External Tools.

Klicken Sie im Dialogfeld Externe Tools auf Add und geben Sie im Feld Titel den öffentlichen Schlüssel für Assembly ein.

Füllen Sie das Befehlsfeld aus, indem Sie zu sn.exe navigieren. Es wird normalerweise an folgendem Speicherort installiert: C:\Programme (x86)\Microsoft SDKs\Windows\v7.0a\Bin\x64\sn.exe.

Geben Sie im Feld Argumente Folgendes ein (Groß- und Kleinschreibung beachten): -Tp $ (TargetPath) . Aktivieren Sie das Kontrollkästchen Ausgabefenster verwenden.

Klicken Sie auf OK. Der neue Befehl wird dem Menü Extras hinzugefügt.

Wenn Sie das Token für den öffentlichen Schlüssel der Assembly benötigen, die Sie gerade entwickeln, klicken Sie im Menü Extras auf den Befehl Assembly-öffentlichen Schlüssel abrufen. Das Token für den öffentlichen Schlüssel wird im Ausgabefenster angezeigt.

Vorherige Antworten mit PublicKey haben funktioniert: (Visual Studio 2015: NEED muss sich in einer Zeile befinden, andernfalls wird beschwert, dass die Assemblyreferenz ungültig ist oder nicht referenziert werden kann. PublicKeyToken hat nicht funktioniert)

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

Danke an @Joe

So erhalten Sie den öffentlichen Schlüssel der Freundesversammlung:

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

In einer Developper-Eingabeaufforderung (Start> Programme> Visual Studio 2015> Visual Studio-Tools> Eingabeaufforderung für Entwickler für VS2015) . Vielen Dank an @Ian G.

Nach dem Vorstehenden war es für mich das Endlichste, das Projekt meiner Freundesbibliothek auf die gleiche Weise zu signieren, wie das Projekt der Bibliothek, das freigegeben werden soll. Da es sich um eine neue Testbibliothek handelt, wurde sie noch nicht signiert.

2
Micaël

Ich schreibe das aus Frustration. Stellen Sie sicher, dass die Assembly, der Sie Zugriff gewähren, wie erwartet benannt wird.

Ich habe mein Projekt umbenannt, der Assemblyname wird dadurch jedoch nicht automatisch aktualisiert. Klicken Sie mit der rechten Maustaste auf Ihr Projekt und klicken Sie auf Eigenschaften. Stellen Sie unter Application sicher, dass der Assemblyname und Default Namespace das ist, was Sie erwarten.

1
Kameron Kincade

Gilt nur, wenn Sie nicht signierte Assemblys als nicht signierte Assembly behalten möchten (und sie aus mehreren Gründen nicht signieren möchten):

Es gibt noch einen weiteren Punkt: Wenn Sie Ihre Basisbibliothek von VS.Net in ein lokales Verzeichnis kompilieren, funktioniert sie möglicherweise wie erwartet.

ABER: Sobald Sie Ihre Basisbibliothek auf einem Netzwerklaufwerk kompilieren, gelten Sicherheitsrichtlinien und die Assembly kann nicht erfolgreich geladen werden. Dies führt erneut dazu, dass VS.NET oder der Compiler beim Überprüfen der PublicKey-Übereinstimmung fehlschlagen.

ENDLICH ist es möglich, nicht signierte Assemblys zu verwenden: https://msdn.Microsoft.com/en-us/library/bb384966.aspx Sie müssen sicherstellen, dass BEIDE Assemblys NICHT SIGNIERT sind, und das Assembly-Attribut muss sein ohne PublicKey-Angabe:

<Assembly: InternalsVisibleTo("friend_unsigned_B")>

1
Jochen

Ich hatte das gleiche Problem. Keine der Lösungen funktionierte.

Schließlich wurde festgestellt, dass das Problem auf eine explizite Implementierung der Schnittstelle Y durch die Klasse X zurückzuführen war, die intern ist.

die Methode X.InterfaceMethod war nicht verfügbar, obwohl ich keine Ahnung habe, warum.

Die Lösung bestand darin, (X als YourInterface) .InterfaceMethod in die Testbibliothek zu konvertieren, und dann funktionierten die Dinge. 

1
Sentinel

Wenn Sie über mehr als eine Assembly verfügen, auf die verwiesen wird, überprüfen Sie, ob alle erforderlichen Assemblys das Attribut InternalsVisibleTo besitzen. Manchmal ist es nicht offensichtlich und es ist keine Nachricht, dass Sie dieses Attribut in eine andere Assembly einfügen müssen.

0
VladExL

Als Randbemerkung: Wenn Sie einfach den öffentlichen Schlüssel erhalten möchten, ohne sn zu verwenden und seine Optionen herauszufinden, können Sie das praktische Programm hier herunterladen. Er bestimmt nicht nur den öffentlichen Schlüssel, sondern erstellt auch die Zeile "Assembly: InternalsVisibleTo ...", die in die Zwischenablage kopiert und in Ihren Code eingefügt werden kann.

0
Bill W

1- Unterzeichnen Sie das Testprojekt: Gehen Sie in Visual Studio zum Eigenschaftsfenster von dem Testprojekt und Signieren Sie die Assembly , indem Sie das Kontrollkästchen mit derselben Phrase in Signing markieren. Tab.

2- Erstellen Sie einen PublicKey für das Testprojekt: Öffnen Sie die Visual Studio-Eingabeaufforderung (z. B. die Entwickler-Eingabeaufforderung für VS 2017). Wechseln Sie in den Ordner, in dem sich die .dll-Datei von the test project befindet. Erstellen Sie einen öffentlichen Schlüssel über sn.exe:

sn -Tp TestProject.dll

Beachten Sie, dass das Argument -Tp ist, aber nicht -tp.

3- Führen Sie den PublicKey in das zu testende Projekt ein: Gehen Sie zur Datei AssemblyInfo.cs in das zu testende Projekt und fügen Sie diese Zeile mit dem im vorherigen Schritt erstellten PublicKey hinzu:

[Montage: InternalsVisibleTo ( " TestProjectAssemblyName , PublicKey = 2066212d128683a85f31645c60719617ba512c0bfdba6791612ed56350368f6cc40a17b4942ff16cda9e760684658fa3f357c137a1005b04cb002400000480000094000000060200000024000052534131000400000100010065fe67a14eb30ffcdd99880e9d725f04e5c720dffc561b23e2953c34db8b7c5d4643f476408ad1b1e28d6bde7d64279b0f51bf0e60be2d383a6c497bf27307447506b746bd2075")]

Vergessen Sie nicht, den obigen PublicKey durch Ihren zu ersetzen.

4- Machen Sie die private Methode intern: Ändern Sie im zu testenden Projekt den Zugriffsmodifizierer der Methode auf internal.

interne statische void DoSomething () {...}

0
user3029066

Ich habe gerade ein ähnliches Problem mit dem InternalsVisibleTo-Attribut gelöst. Alles schien richtig und ich konnte nicht verstehen, warum die interne Klasse, auf die ich zielte, immer noch nicht erreichbar war.

Das Problem wurde behoben, indem der Schlüssel zwischen Groß- und Kleinschreibung geändert wurde. 

0
Keysharpener