Ich versuche, das InternalsVisibleTo
Assembly-Attribut zu verwenden, um meine internen Klassen in einer .NET-Klassenbibliothek für mein Unit-Test-Projekt sichtbar zu machen. Aus irgendeinem Grund erhalte ich immer wieder die Fehlermeldung:
Auf 'MyClassName' kann aufgrund seiner Schutzstufe nicht zugegriffen werden
Beide Assemblys sind signiert und ich habe den richtigen Schlüssel in der Attributdeklaration aufgeführt. Irgendwelche Ideen?
Antworten:
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 für den öffentlichen Schlüssel. Es sieht ungefähr so aus:
[assembly: InternalsVisibleTo("MyFriendAssembly, PublicKey=0024000004800000940000000602000000240000525341310004000001000100F73 F4DDC11F0CA6209BC63EFCBBAC3DACB04B612E04FA07F01D919FB5A1579D20283DC12901C8B66 A08FB8A9CB6A5E81989007B3AA43CD7442BED6D21F4D33FB590A46420FB75265C889D536A9519 674440C3C2FB06C5924360243CACD4B641BE574C31A434CE845323395842FAAF106B234C2C140 6E2F553073FF557D2DB6C5")]
Es sind ungefähr 320 hexadezimale Ziffern. Sie sind sich nicht sicher, warum Sie den vollständigen öffentlichen Schlüssel angeben müssen. Möglicherweise ist es für jemanden mit nur dem Token für den öffentlichen Schlüssel, das in anderen Assemblyreferenzen verwendet wird, einfacher, die Identität der befreundeten Assembly zu fälschen.
quelle
sn.exe -Tp NameOfAssembly
odersn - Tp NameOfAssembly
wie Ian sagte ein. Hierbei wird das Strong Name Tool von Microsoft verwendet, um den vollständigen öffentlichen Schlüssel aus der Assembly zu finden und anzuzeigen. Wenn Sie nur eine .pub-Datei haben, die Ihren Schlüssel enthält, können Sie diese mit extrahierensn.exe -p NameOfKeyFile.snk NameOfKeyPairFile.pub
. Dadurch wird die Schlüsseldatei NameOfKeyFile.snk erstellt, mit der Sie die vorherigen Anweisungen befolgen können.[assembly:InternalsVisibleTo("...")]
Attribut trotz der offensichtlichen Formatierung des Beispiels hier und in der MSDN-Dokumentation in einer einzelnen Zeile steht . Sie können die Ausgabe des öffentlichen Schlüssels nicht einfach kopieren und einfügensn.exe -Tp MyFriendAssembly
und dann ein@"multi line string"
(beachten Sie das @ -Zeichen)...does not contain a definition for 'X' and no extension method 'X' ... could be found
verwenden. Andernfalls beschwert sich der Compiler, wenn Sie versuchen, über MyFriendAssembly auf Ihre Interna zuzugreifen.-T $(TargetPath)
durch-Tp $(TargetPath)
Ein weiteres mögliches "gotcha": Der Name der Freund-Assembly, den Sie in angeben,
InternalsVisibleToAttribute
muss genau mit dem Namen Ihrer Freund-Assembly übereinstimmen, wie in den Projekteigenschaften des Freundes (auf der Registerkarte Anwendung) angegeben.In meinem Fall hatte ich ein Projekt
Thingamajig
und ein BegleitprojektThingamajigAutoTests
(Namen wurden geändert, um die Schuldigen zu schützen), die beide nicht signierte Baugruppen hervorbrachten. Ich habe das Attribut ordnungsgemäß[assembly: InternalsVisibleTo( "ThingamajigAutoTests" )]
zur Datei Thingamajig \ AssemblyInfo.cs hinzugefügt und die AttributeAssemblyKeyFile
undAssemblyKeyName
wie oben angegeben auskommentiert . DasThingamajig
Projekt lief einwandfrei, aber seine internen Mitglieder weigerten sich hartnäckig, im Autotest-Projekt aufzutauchen.Nach
ThingamajigAutoTests
langem Kopfkratzen überprüfte ich die Projekteigenschaften erneut und stellte fest, dass der Assemblyname als "ThingamajigAutoTests.dll" angegeben wurde. Bingo - Ich habe dem Assemblernamen imInternalsVisibleTo
Attribut die Erweiterung ".dll" hinzugefügt , und die Teile wurden zusammengefügt.Manchmal sind es die kleinsten Dinge ...
quelle
Wenn Ihre Assemblys nicht signiert sind, aber immer noch der gleiche Fehler angezeigt wird, überprüfen Sie Ihre AssemblyInfo.cs-Datei auf eine der folgenden Zeilen:
[assembly: AssemblyKeyFile("")] [assembly: AssemblyKeyName("")]
Auf der Registerkarte "Eigenschaften" wird Ihre Baugruppe weiterhin als vorzeichenlos angezeigt, wenn eine (oder beide) dieser Zeilen vorhanden sind. Das Attribut "InternalsVisibleTo" behandelt eine Baugruppe mit diesen Zeilen jedoch als stark signiert. Löschen Sie einfach diese Zeilen (oder kommentieren Sie sie aus), und es sollte für Sie gut funktionieren.
quelle
Es ist erwähnenswert, dass Sie Folgendes verwenden müssen, wenn die Assembly "friend" (Tests) in C ++ / CLI und nicht in C # / VB.Net geschrieben ist:
#using "AssemblyUnderTest.dll" as_friend
anstelle einer Projektreferenz oder der üblichen
#using
Aussage. Aus irgendeinem Grund gibt es in der Projektreferenz-Benutzeroberfläche keine Möglichkeit, dies zu tun.quelle
Sie können das AssemblyHelper-Tool verwenden , das die InternalsVisibleTo-Syntax für Sie generiert. Hier ist der Link zur neuesten Version . Beachten Sie nur, dass dies nur für stark benannte Assemblys funktioniert.
quelle
Hier ist ein Makro, mit dem ich dieses Attribut schnell generiere. Es ist ein bisschen hacky, aber es funktioniert. Auf meiner Maschine. Wenn die zuletzt signierte Binärdatei aktiviert ist
/bin/debug
. Usw. Zweideutigkeit usw. Wie auch immer, Sie können sehen, wie es den Schlüssel bekommt, so dass Sie einen Hinweis geben. Korrigieren / verbessern Sie, 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
quelle
Sie müssen den Kompilierungsschalter / out: verwenden, wenn Sie die Friend-Assembly kompilieren (die Assembly, die das InternalsVisibleTo-Attribut nicht enthält).
Der Compiler muss den Namen der zu kompilierenden Assembly kennen, um zu bestimmen, ob die resultierende Assembly als Friend-Assembly betrachtet werden soll.
quelle
/out
Option hinzu, wenn die .msbuild-Datei die folgenden Zeilen enthält :<PropertyGroup> <AssemblyName>YourFriendAssemblyName</AssemblyName> </PropertyGroup>
. Dies kann auch in den Projekteigenschaften auf der Registerkarte "Anwendung" im Feld "Baugruppenname" festgelegt werden.Zusätzlich zu all dem kann das Problem gelöst werden , wenn alles korrekt zu sein scheint, die Friend-Assembly sich jedoch hartnäckig weigert, Interna zu sehen. Ein erneutes Laden der Lösung oder ein Neustart von Visual Studio können das Problem lösen.
quelle
Sie müssen einen neuen vollständigen öffentlichen Schlüssel für die Assembly generieren und dann das Attribut für die Assembly angeben.
[assembly: InternalsVisibleTo("assemblyname, PublicKey="Full Public Key")]
Führen Sie die folgenden MSDN- Schritte aus, um aus Visual Studio einen neuen vollständigen öffentlichen Schlüssel für die Assembly zu generieren.
So fügen Sie dem Menü "Extras" ein Element "Öffentlichen Schlüssel abrufen" hinzu
Klicken Sie in Visual Studio im Menü Extras auf Externe Tools .
Klicken Sie im Dialogfeld Externe Tools auf Hinzufügen und geben Sie im Titelfeld Get Assembly Public Key ein.
Füllen Sie das Befehlsfeld aus, indem Sie zu sn.exe navigieren. Es wird normalerweise am folgenden 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 entwickeln, klicken Sie im Menü Extras auf den Befehl Öffentlichen Schlüssel für Assembly abrufen. Das Token für den öffentlichen Schlüssel wird im Ausgabefenster angezeigt.
quelle
C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\sn.exe
In meinem Fall mit VS.Net 2015, musste ich unterzeichnen BEIDE Baugruppen (wenn mindestens 1 Montage unterzeichnet werden soll oder Sie wollen Bezug auf den öffentlichen Schlüssel der Assembly).
In meinem Projekt wurde überhaupt nicht signiert. Also begann ich, meiner Testbibliothek einen Vorzeichenschlüssel hinzuzufügen und das InternalsVisibleTo-Attribut in der Basisbibliothek meines Projekts zu verwenden. Aber VS.Net erklärte immer, dass es nicht auf die Friend-Methoden zugreifen konnte.
Als ich anfing, die Basisbibliothek zu signieren (es kann der gleiche oder ein anderer Signaturschlüssel sein - solange Sie die Basisbibliothek signieren), konnte VS.Net sofort wie erwartet arbeiten.
quelle
Frühere Antworten mit PublicKey haben funktioniert: (Visual Studio 2015: MUSS in einer Zeile stehen, andernfalls wird beanstandet, 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
Innerhalb einer Developper-Eingabeaufforderung (Start> Programme> Visual Studio 2015> Visual Studio-Tools> Entwickler-Eingabeaufforderung für VS2015). Vielen Dank an @Ian G.
Der letzte Schliff, der es nach dem oben Gesagten für mich zum Funktionieren brachte, war, mein Bibliotheksprojekt für Freunde genauso zu signieren, wie das Projekt der zu teilenden Bibliothek signiert ist. Da es sich um eine neue Testbibliothek handelte, war sie noch nicht signiert.
quelle
Eine weitere Möglichkeit, die je nach Schreibweise Ihres Codes schwierig zu finden sein kann.
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 in Y auf ZType beziehen, nachdem Sie Y als Freund von X hinzugefügt haben, sind Sie möglicherweise verwirrt, warum Ihr Code immer noch nicht kompiliert wird.
Der Kompilierungsfehler könnte in diesem Fall definitiv hilfreicher sein.
quelle
Ich schreibe das aus Frustration. Stellen Sie sicher, dass die Assembly, auf die Sie Zugriff gewähren, wie erwartet benannt ist.
Ich habe mein Projekt umbenannt, aber dadurch wird der Baugruppenname nicht automatisch aktualisiert. Klicken Sie mit der rechten Maustaste auf Ihr Projekt und klicken Sie auf Eigenschaften . Stellen Sie unter Anwendung sicher, dass der Assemblyname und der Standardnamespace Ihren Erwartungen entsprechen.
quelle
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 dies 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 fehlschlägt, wenn nach der PublicKey-Übereinstimmung gesucht wird.
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 keine PublicKey-Informationen enthalten muss:
<Assembly: InternalsVisibleTo("friend_unsigned_B")>
quelle
Ich hatte das gleiche Problem. Keine der Lösungen funktionierte.
Schließlich wurde festgestellt, dass das Problem darauf zurückzuführen ist, dass Klasse X die interne Schnittstelle Y explizit implementiert.
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 übertragen, und dann funktionierten die Dinge.
quelle
Nebenbei bemerkt, wenn Sie den öffentlichen Schlüssel einfach erhalten möchten, ohne sn verwenden zu müssen und seine Optionen herauszufinden, können Sie das praktische Programm hier herunterladen . Es bestimmt nicht nur den öffentlichen Schlüssel, sondern erstellt auch die Zeile "Assembly: InternalsVisibleTo ...", die zum Kopieren in die Zwischenablage und zum Einfügen in Ihren Code bereit ist.
quelle
Ich habe gerade ein ähnliches Problem mit dem
InternalsVisibleTo
Attribut gelöst . Alles schien richtig zu sein und ich konnte nicht herausfinden, warum die interne Klasse, die ich anstrebte, immer noch nicht zugänglich war.Durch Ändern der Groß- und Kleinschreibung des Schlüssels wurde das Problem behoben.
quelle
Wenn Sie mehr als eine Assembly haben, auf die verwiesen wird, überprüfen Sie, ob alle erforderlichen Assemblys das Attribut InternalsVisibleTo haben. Manchmal ist es nicht offensichtlich und keine Meldung, dass Sie dieses Attribut einer anderen Assembly hinzufügen müssen.
quelle
1- Signieren Sie das Testprojekt: Gehen Sie in Visual Studio zum Eigenschaftenfenster des Testprojekts und signieren Sie die Assembly, indem Sie das Kontrollkästchen mit demselben Satz auf der Registerkarte Signieren aktivieren.
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 des Testprojekts befindet. Erstellen Sie einen öffentlichen Schlüssel über sn.exe:
sn -Tp TestProject.dll
Beachten Sie, dass das Argument -Tp, aber nicht -tp ist.
3- Einführung in das PublicKey des Projekt getestet werden: Gehen Sie auf die Datei AssemblyInfo.cs in dem Projekt getestet werden und diese Zeile mit dem im vorherigen Schritt erstellt PublicKey hinzu:
[assembly: InternalsVisibleTo (“ TestProjectAssemblyName , PublicKey = 2066212d128683a85f31645c60719617ba512c0bfdba6791612ed56350368f6cc40a17b4942ff16cda9e760684658fa3f357c137a1005b04cb002400000480000094000000060200000024000052534131000400000100010065fe67a14eb30ffcdd99880e9d725f04e5c720dffc561b23e2953c34db8b7c5d4643f476408ad1b1e28d6bde7d64279b0f51bf0e60be2d383a6c497bf27307447506b746bd2075" )]
Vergessen Sie nicht, den oben genannten PublicKey durch Ihren zu ersetzen.
4- Machen Sie die private Methode intern: Ändern Sie im zu testenden Projekt den Zugriffsmodifikator der Methode in intern.
interne statische Leere DoSomething () {...}
quelle