InternalsVisibleTo attribute no funciona

Intento utilizar el atributo de ensamblaje InternalsVisibleTo para hacer que mis clases internas en una biblioteca de clases .NET sean visibles para mi proyecto de prueba de unidad. Por alguna razón, sigo recibiendo un mensaje de error que dice:

‘MyClassName’ es inaccesible debido a su nivel de protección

Ambos ensamblajes están firmados y tengo la clave correcta en la lista en la statement de atributo. ¿Algunas ideas?

¿Estás absolutamente seguro de que tienes la clave pública correcta especificada en el atributo? Tenga en cuenta que debe especificar la clave pública completa, no solo la clave pública de token. Se ve algo así como:

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

Son 320 o más dígitos hexagonales. No estoy seguro de por qué necesita especificar la clave pública completa; posiblemente con solo el token de clave pública que se usa en otras referencias de ensamblaje, sería más fácil para alguien burlar la identidad de la ensambladora amiga.

Otro posible “gotcha”: el nombre del conjunto de amigos que especifique en InternalsVisibleToAttribute debe coincidir exactamente con el nombre de su conjunto de amigos como se muestra en las propiedades del proyecto del amigo (en la pestaña Aplicación).

En mi caso, tenía un proyecto Thingamajig y un proyecto complementario ThingamajigAutoTests (nombres cambiados para proteger a los culpables) que producían ensamblajes sin firmar. He añadido debidamente el atributo [assembly: InternalsVisibleTo( "ThingamajigAutoTests" )] al archivo Thingamajig \ AssemblyInfo.cs, y comenté los atributos AssemblyKeyFile y AssemblyKeyName como se indicó anteriormente. El proyecto Thingamajig , pero sus miembros internos obstinadamente se negaron a aparecer en el proyecto de autotest.

Después de mucho scratching, volví a comprobar las propiedades del proyecto ThingamajigAutoTests y descubrí que el nombre del ensamblado se había especificado como “ThingamajigAutoTests.dll”. Bingo: agregué la extensión “.dll” al nombre del ensamblado en el atributo InternalsVisibleTo , y las piezas cayeron en su lugar.

A veces son las cosas más pequeñas …

Si sus ensamblajes no están firmados, pero aún obtiene el mismo error, verifique su archivo AssemblyInfo.cs para una de las siguientes líneas:

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

La pestaña de propiedades seguirá mostrando su ensamblaje como no firmado si cualquiera (o ambas) de estas líneas están presentes, pero el atributo InternalsVisibleTo trata un ensamblaje con estas líneas como fuertemente firmado. Simplemente elimine (o comente) estas líneas, y debería funcionar bien para usted.

Vale la pena señalar que si el ensamblado “amigo” (pruebas) está escrito en C ++ / CLI, en lugar de C # / VB.Net, entonces necesita usar lo siguiente:

 #using "AssemblyUnderTest.dll" as_friend 

en lugar de una referencia de proyecto o la habitual statement #using. Por alguna razón, no hay forma de hacerlo en la interfaz de usuario de referencia del proyecto.

Colin

Puede usar la herramienta AssemblyHelper que generará la syntax de InternalsVisibleTo para usted. Aquí está el enlace a la última versión . Solo tenga en cuenta que solo funciona para conjuntos fuertemente nombrados.

Aquí hay una macro que uso para generar rápidamente este atributo. Es un poco raro, pero funciona. En mi máquina. Cuando el último binario con signo está en /bin/debug . Equivocación Etc etc. De todos modos, puede ver cómo obtiene la clave, por lo que le dará una pista. Arregle / mejore según lo permita su tiempo.

 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 

Debe usar el modificador de comstackción / out: al comstackr el conjunto de amigos (el conjunto que no contiene el atributo InternalsVisibleTo).

El comstackdor necesita saber el nombre del ensamblado que se está comstackndo para determinar si el conjunto resultante se debe considerar como un ensamblado amigo.

Además de todo lo anterior, cuando todo parece correcto, pero el conjunto de amigos obstinadamente se niega a ver ningún elemento interno, volver a cargar la solución o reiniciar Visual Studio puede resolver el problema.

En mi caso usando VS.Net 2015, necesitaba firmar AMBAS asambleas (si al menos 1 ensamble debe estar firmado o si desea hacer referencia en la clave pública de su ensamblaje).

Mi proyecto no usó la firma en absoluto. Así que comencé a agregar una clave de firma a mi biblioteca de prueba y el uso de InternalsVisibleTo-Attribute en la biblioteca base de mi proyecto. Pero VS.Net siempre explicó que no podía acceder a los métodos de amigos.

Cuando comencé a firmar la biblioteca base (puede ser la misma u otra clave de firma, siempre que firme la biblioteca base), VS.Net pudo funcionar inmediatamente como se esperaba.

Las respuestas anteriores con PublicKey funcionaron: (Visual Studio 2015: NECESITA estar en una línea, de lo contrario se queja de que la referencia de ensamblado no es válida o no se puede hacer referencia. PublicKeyToken no funcionó)

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

Gracias a @Joe

Para obtener la clave pública de la asamblea de amigos:

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

Dentro de un indicador de comando de Desarrollador (Inicio> Progtwigs> Visual Studio 2015> Herramientas de Visual Studio> Indicador de comando del desarrollador para VS2015). Gracias a @Ian G.

Aunque, el toque final que hizo que funcionara para mí después de lo anterior fue firmar mi proyecto de biblioteca amigo de la misma manera que el proyecto de la biblioteca para compartir está firmado. Como era una nueva biblioteca de prueba, aún no se había firmado.

Debe generar una nueva clave pública completa para el ensamblaje y luego especificar el atributo para ensamblar.

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

Siga los pasos de MSDN a continuación para generar una nueva clave pública completa para el ensamblaje desde Visual Studio.

Para agregar un elemento Obtener clave pública de ensamblaje al menú Herramientas

En Visual Studio, haga clic en Herramientas externas en el menú Herramientas.

En el cuadro de diálogo Herramientas externas, haga clic en Agregar e ingrese Obtener clave pública de ensamblaje en el cuadro Título.

Complete el cuadro Comando navegando a sn.exe. Normalmente se instala en la siguiente ubicación: C: \ Archivos de progtwig (x86) \ Microsoft SDKs \ Windows \ v7.0a \ Bin \ x64 \ sn.exe .

En el cuadro Argumentos, escriba lo siguiente (distingue entre mayúsculas y minúsculas): -Tp $ (TargetPath) . Seleccione la checkbox Usar ventana de salida.

Haga clic en Aceptar . El nuevo comando se agrega al menú Herramientas.

Siempre que necesite el Token de clave pública del ensamblado que está desarrollando, haga clic en el comando Obtener clave pública de ensamblaje en el menú Herramientas, y el token de clave pública aparecerá en la ventana de Salida.

Otra posibilidad que puede ser difícil de rastrear, según cómo esté escrito su código.

  1. Está invocando un método interno definido en X de otro conjunto Y
  2. La firma del método usa tipos internos definidos en Z
  3. Luego debe agregar [InternalsVisibleTo] en X AND en Z

Por ejemplo:

 // In X internal static class XType { internal static ZType GetZ() { ... } } // In Y: object someUntypedValue = XType.GetZ(); // In Z: internal class ZType { ... } 

Si lo tiene escrito como se indica arriba, donde no se está refiriendo directamente a ZType en Y, después de haber agregado a Y como amigo de X, puede desconcertar por qué su código aún no se comstack.

El error de comstackción definitivamente podría ser más útil en este caso.

Solo se aplica si desea mantener ensamblajes sin firmar como ensamblaje sin firmar (y no desea firmarlo por varias razones):

Todavía hay otro punto: si comstack su biblioteca base de VS.Net a un directorio local, puede funcionar como se espera.

PERO: tan pronto como comstack su biblioteca base en una unidad de red, se aplican las políticas de seguridad y el ensamblaje no se puede cargar correctamente. De nuevo, esto hace que VS.NET o el comstackdor fallen al verificar la coincidencia de PublicKey.

FINALMENTE, es posible usar ensamblajes sin firmar: https://msdn.microsoft.com/en-us/library/bb384966.aspx Debe asegurarse de que AMBOS ensambles NO ESTEN FIRMADOS y que el atributo de ensamblaje no tenga información de PublicKey:

Como nota al margen, si quiere obtener fácilmente la clave pública sin tener que usar sn y descubrir sus opciones, puede descargar el útil progtwig aquí . No solo determina la clave pública sino que también crea la línea “assembly: InternalsVisibleTo …” lista para ser copiada al portapapeles y pegada en su código.

Acabo de resolver un problema similar con el atributo InternalsVisibleTo Attribute. Todo parecía estar bien y no podía entender por qué la clase interna que apuntaba todavía no era accesible.

Cambiar el caso de la llave de mayúscula a minúscula solucionó el problema.

Estoy escribiendo esto por frustración. Asegúrese de que el conjunto al que está otorgando acceso tenga el nombre que espera.

Cambié el nombre de mi proyecto, pero esto no actualiza automáticamente el Nombre del ensamblado. Haga clic derecho en su proyecto y haga clic en Propiedades . En Aplicación , asegúrese de que el Nombre de conjunto y el Espacio de nombre predeterminado sean los que espera.

Si tiene más de 1 conjunto referenciado, verifique que todos los ensamblajes necesarios tengan el atributo InternalsVisibleTo. A veces no es obvio, y no hay mensaje de que tenga que agregar este atributo en el otro ensamblaje.

Yo tuve el mismo problema. Ninguna de las soluciones funcionó.

Eventualmente descubrieron que el problema se debía a que la clase X implementaba explícitamente la interfaz Y, que es interna.

el método X.InterfaceMethod no estaba disponible, aunque no tengo idea de por qué.

La solución fue convertir (X como YourInterface) .InterfaceMethod en la biblioteca de prueba, y luego las cosas funcionaron.