Domanda

Sto cercando di utilizzare l'attributo InternalsVisibleTo assembly per rendere visibili le mie classi interne in una libreria di classi .NET al mio progetto di unit test. Per qualche motivo, continuo a ricevere un messaggio di errore che dice:

  

"MyClassName" è inaccessibile a causa del suo livello di protezione

Entrambi gli assiemi sono firmati e ho la chiave corretta elencata nella dichiarazione dell'attributo. Qualche idea?

È stato utile?

Soluzione

Sei assolutamente sicuro di avere la chiave pubblica corretta specificata nell'attributo? Nota che devi specificare la chiave pubblica completa, non solo il token della chiave pubblica. Sembra qualcosa del tipo:

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

Sono circa 320 cifre esadecimali. Non sono sicuro del motivo per cui è necessario specificare la chiave pubblica completa, possibilmente con solo il token della chiave pubblica utilizzato in altri riferimenti di assembly, sarebbe più facile per qualcuno falsificare l'identità dell'assembly amico.

Altri suggerimenti

Un altro possibile " gotcha " ;: Il nome dell'assembly amico specificato in InternalsVisibleToAttribute deve esattamente corrispondere al nome dell'assembly amico come mostrato in le proprietà del progetto dell'amico (nella scheda Applicazione).

Nel mio caso, avevo un progetto Thingamajig e un progetto complementare ThingamajigAutoTests (nomi cambiati per proteggere i colpevoli) che entrambi producevano assiemi non firmati. Ho debitamente aggiunto l'attributo [assembly: InternalsVisibleTo( "ThingamajigAutoTests" )] al file Thingamajig \ AssemblyInfo.cs e ho commentato gli attributi AssemblyKeyFile e AssemblyKeyName come indicato sopra. Il InternalsVisibleTo progetto è stato realizzato bene, ma i suoi membri interni si sono ostinatamente rifiutati di presentarsi nel progetto di autotest.

Dopo molti graffi alla testa, ho ricontrollato le <=> proprietà del progetto e ho scoperto che il nome dell'assembly è stato specificato come " ThingamajigAutoTests.dll " ;. Bingo - Ho aggiunto il & Quot; .dll & Quot; estensione al nome dell'assembly nell'attributo <=> e i pezzi sono andati a posto.

A volte sono le cose più piccole ...

Se i tuoi assembly non sono firmati, ma stai ancora riscontrando lo stesso errore, controlla il tuo file AssemblyInfo.cs per una delle seguenti righe:

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

La scheda delle proprietà mostrerà comunque l'assembly come senza segno se è presente una (o entrambe) queste linee, ma l'attributo InternalsVisibleTo considera un assieme con queste linee come fortemente segnato. Basta eliminare (o commentare) queste righe e dovrebbe funzionare bene per te.

Vale la pena notare che se " amico " (test) assembly è scritto in C ++ / CLI, anziché in C # / VB.Net quindi è necessario utilizzare quanto segue:

#using "AssemblyUnderTest.dll" as_friend

invece di un riferimento al progetto o la solita istruzione #using. Per qualche motivo, non è possibile farlo nell'interfaccia utente di riferimento del progetto.

Puoi utilizzare Strumento AssemblyHelper che genererà InternalsVisibleTo sintassi per te. Ecco il link all'ultima versione . Basta notare che funziona solo per assiemi con un nome sicuro.

Ecco una macro che uso per generare rapidamente questo attributo. È un po 'confuso, ma funziona. Sulla mia macchina Quando l'ultimo binario firmato è in /bin/debug. Ecc. Equivoco ecc. Comunque, puoi vedere come ottiene la chiave, in modo che ti dia un suggerimento. Risolvi / migliora quando il tuo tempo lo consente.

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

È necessario utilizzare l'opzione / out: compilatore durante la compilazione dell'assembly amico (l'assembly che non contiene l'attributo InternalsVisibleTo).

Il compilatore deve conoscere il nome dell'assembly in fase di compilazione per determinare se l'assembly risultante deve essere considerato un assembly amico.

Oltre a tutto quanto sopra, quando tutto sembra essere corretto, ma l'assemblea di amici rifiuta ostinatamente di vedere eventuali interni, ricaricare la soluzione o riavviare Visual Studio può risolvere il problema.

Nel mio caso usando VS.Net 2015, dovevo firmare ENTRAMBI gli assiemi (se almeno 1 assembly deve essere firmato o vuoi fare riferimento sulla chiave pubblica dell'assembly).

Il mio progetto non ha usato affatto la firma. Così ho iniziato ad aggiungere una chiave di segno alla mia libreria di test e ad utilizzare InternalsVisibleTo-Attribute nella libreria di base del mio progetto. Ma VS.Net ha sempre spiegato che non poteva accedere ai metodi degli amici.

Quando ho iniziato a firmare la libreria di base (può essere la stessa o un'altra chiave di segno - purché firmi la libreria di base), VS.Net è stato immediatamente in grado di funzionare come previsto.

Risposte precedenti con PublicKey funzionavano: (Visual Studio 2015: DEVE essere su una riga, altrimenti si lamenta che il riferimento all'assembly non è valido o non è possibile fare riferimento. PublicKeyToken non ha funzionato)

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

Grazie a @Joe

Per ottenere la chiave pubblica dell'assembly amico:

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

All'interno di un prompt dei comandi di Developper (Avvio > Programmi > Visual Studio 2015 > Visual Studio Tools > Prompt dei comandi per sviluppatori per VS2015). Grazie a @Ian G.

Anche se, il tocco finale che mi ha fatto funzionare dopo quanto sopra è stato quello di firmare il progetto del mio amico biblioteca allo stesso modo in cui è firmato il progetto della biblioteca da condividere. Poiché era una nuova libreria Test, non era ancora firmata.

È necessario generare una nuova chiave pubblica completa per l'assembly e quindi specificare l'attributo all'assembly.

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

Segui il MSDN passaggi per generare una nuova chiave pubblica completa per l'assembly da Visual Studio.

Per aggiungere una voce Ottieni chiave pubblica assembly al menu Strumenti

In Visual Studio, fai clic su Strumenti esterni dal menu Strumenti.

Nella finestra di dialogo Strumenti esterni, fai clic su Aggiungi e inserisci Ottieni chiave pubblica assembly nella casella Titolo.

Compilare la casella di comando passando a sn.exe. In genere viene installato nel seguente percorso: C: \ Programmi (x86) \ Microsoft SDKs \ Windows \ v7.0a \ Bin \ x64 \ sn.exe .

Nella casella Argomenti, digitare quanto segue (case sensitive): -Tp $ (TargetPath) . Seleziona la casella di controllo Usa finestra di output.

Fai clic su OK . Il nuovo comando viene aggiunto al menu Strumenti.

Ogni volta che è necessario il token di chiave pubblica dell'assembly che si sta sviluppando, fare clic sul comando Ottieni chiave pubblica di assembly dal menu Strumenti e il token di chiave pubblica appare nella finestra Output.

Un'altra possibilità che può essere difficile da rintracciare, a seconda di come è scritto il tuo codice.

  1. Stai invocando un metodo interno definito in X da un altro assembly Y
  2. La firma del metodo utilizza tipi interni definiti in Z
  3. Devi quindi aggiungere [InternalsVisibleTo] in X AND in Z

Ad esempio:

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

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

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

Se lo hai scritto come sopra, dove non ti riferisci a ZType direttamente in Y, dopo aver aggiunto Y come amico di X, potresti essere sconcertato perché il tuo codice non viene ancora compilato.

L'errore di compilazione potrebbe sicuramente essere più utile in questo caso.

Si applica solo se si desidera mantenere gli assembly senza segno come assembly senza segno (e non si desidera firmarlo per diversi motivi):

C'è ancora un altro punto: se si compila la libreria di base da VS.Net in una directory locale, potrebbe funzionare come previsto.

MA: non appena si compila la libreria di base su un'unità di rete, si applicano i criteri di sicurezza e l'assembly non può essere caricato correttamente. Ciò causa nuovamente VS.NET o il compilatore quando si verifica la corrispondenza PublicKey.

FINALMENTE, è possibile utilizzare gli assembly senza segno: https://msdn.microsoft.com/en-us/library/bb384966.aspx È necessario assicurarsi che ENTRAMBI gli assemblaggi NON SIANO FIRMATI E l'attributo Assembly deve essere privo di informazioni PublicKey:

<Assembly: InternalsVisibleTo("friend_unsigned_B")>

Sto scrivendo questo per frustrazione. Assicurarsi che l'assembly a cui si sta concedendo l'accesso sia denominato come previsto.

Ho rinominato il mio progetto ma questo non aggiorna automaticamente il Nome assembly. Fare clic con il tasto destro del mouse sul progetto e fare clic su Proprietà . In Applicazione , assicurati che Nome assembly e Spazio dei nomi predefinito siano quelli che ti aspetti.

Ho avuto lo stesso problema. Nessuna delle soluzioni ha funzionato.

Alla fine ho scoperto che il problema era dovuto alla classe X che implementava esplicitamente l'interfaccia Y, che è interna.

il metodo X.InterfaceMethod non era disponibile, anche se non ho idea del perché.

La soluzione era di lanciare (X come YourInterface) .InterfaceMethod nella libreria di test, e poi le cose hanno funzionato.

Come nota a margine, se vuoi ottenere facilmente la chiave pubblica senza dover usare sn e capire le sue opzioni puoi scaricare il pratico programma qui . Non solo determina la chiave pubblica ma crea anche il & Quot; assembly: InternalsVisibleTo ... & Quot; riga pronta per essere copiata negli appunti e incollata nel tuo codice.

Ho appena risolto un problema simile con l'attributo InternalsVisibleTo. Sembrava tutto a posto e non riuscivo a capire perché la classe interna che stavo mirando non fosse ancora accessibile.

La modifica della custodia della chiave da maiuscola a minuscola ha risolto il problema.

Se hai più di 1 assembly referenziato, controlla che tutti gli assembly necessari abbiano l'attributo InternalsVisibleTo. A volte non è ovviamente, e nessun messaggio è necessario aggiungere questo attributo in un altro assembly.

1- Firma il progetto di test: in Visual Studio vai alla finestra delle proprietà di progetto di test e Firma l'assembly controllando il casella di controllo con la stessa frase nella scheda Firma .

2- Crea un tasto pubblico per il progetto di test: apri il prompt dei comandi di Visual Studio (ad es. il prompt dei comandi per sviluppatori per VS 2017). Vai alla cartella in cui esiste il file .dll di progetto di prova . Creare una chiave pubblica tramite sn.exe:

sn -Tp TestProject.dll

Nota che l'argomento è -Tp, ma non -tp.

3- Presenta il PublicKey al progetto da testare: vai al file AssemblyInfo.cs in il progetto da testare e aggiungi questa riga con il PublicKey creato nel passaggio precedente:

[assembly: InternalsVisibleTo (&; & Quot TestProjectAssemblyName , PublicKey = 2066212d128683a85f31645c60719617ba512c0bfdba6791612ed56350368f6cc40a17b4942ff16cda9e760684658fa3f357c137a1005b04cb002400000480000094000000060200000024000052534131000400000100010065fe67a14eb30ffcdd99880e9d725f04e5c720dffc561b23e2953c34db8b7c5d4643f476408ad1b1e28d6bde7d64279b0f51bf0e60be2d383a6c497bf27307447506b746bd2075 quot;)]

Non dimenticare di sostituire il PublicKey sopra con il tuo.

4- Rendi interno il metodo privato: Nel progetto da testare cambia il modificatore di accesso del metodo in interno.

statico interno void DoSomething () {...}

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top