2008-09-20 8 views
62

Estoy intentando utilizar el atributo de ensamblaje InternalsVisibleTo para que mis clases internas en una biblioteca de clases .NET sean visibles para mi proyecto de prueba de unidad. Por alguna razón, Me aparece un mensaje de error que dice:InternalsVisibleAtributo no funciona

'MyClassName' es inaccesible debido a su nivel de protección se firman

Ambos montajes y tengo la llave correcta que aparece en la declaración de atributo . ¿Algunas ideas?

+1

¿Puedes publicar lo que tienes para el atributo InternalsVisibleTo en la clase que intentas exponer? Es difícil decir lo que está mal sin ver lo que estás mirando. –

Respuesta

86

¿Está absolutamente seguro de que tiene 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 token. Se parece a algo así como:

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

Tiene unos 320 dígitos hexadecimales. 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.

+45

Para obtener la clave pública del ensamblado amigo "sn -Tp MyFriendAssembly" –

+27

-1000 para los documentos de MSDN sobre esto, que todavía están incompletos. – Will

+0

genial, entonces ¿cómo obtengo esa^tecla ???? – DevDave

4

Necesita utilizar el modificador/compilador: al compilar el conjunto de amigo (el conjunto que no contiene el atributo InternalsVisibleTo).

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

+0

De forma predeterminada, los destinos de Microsoft C# agregarán la opción '/ out' si el archivo .msbuild contiene las siguientes líneas:' YourFriendAssemblyName '. Esto también se puede establecer en las propiedades del proyecto, en la pestaña "Aplicación", en el campo "Nombre del ensamblado". –

+0

Bingo, ese era mi problema también. ¡Gracias 5 años después! – LLL

10

Cabe noteing que si el "amigo" (pruebas) de montaje está escrito en C++/CLI, en lugar de C#/VB.Net a continuación, es necesario utilizar el siguiente:

#using "AssemblyUnderTest.dll" as_friend 

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

Colin

+1

Wow no sabía que –

35

Si sus asambleas no están firmados, pero aún se está recibiendo el mismo error, compruebe su archivo AssemblyInfo.cs para cualquiera de las siguientes líneas:

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

La ficha de propiedades seguirá mostrando su ensamblaje en calidad sin signo si cualquiera (o ambas) de estas líneas están presentes, pero el atributo InternalsVisibleTo considera que un ensamblado con estas líneas está fuertemente firmado. Simplemente elimine (o comente) estas líneas, y debería funcionar bien para usted.

+1

Gracias, este era mi problema, y ​​en ningún otro lugar podría encontrar esta respuesta. – Andre

+1

Esto me salvó después de obtener "MyAssembly.dll no representa un ensamblado con un nombre fuerte" al llamar sn.exe -Tp MyAssembly.dll – Dunc

5

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 
+0

Gracias @ ¡Lo recordaré la próxima vez! – DevDave

0

Como nota al margen, si se quiere conseguir fácilmente la clave pública sin tener que utilizar sn y averiguar sus opciones se puede descargar el programa de mano here. 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.

0

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

Cambiando la caja de la llave de mayúscula a minúscula solucionó el problema.

35

Otra posible "Gotcha": El nombre del ensamblado amigo que se especifica en el InternalsVisibleToAttribute necesidad exactamente coincidir con el nombre de su amigo el montaje como se muestra en las propiedades del proyecto de su amigo (en la pestaña de Aplicaciones).

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

Después de mucho scratching de la cabeza, 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 ...

+2

+1 como me ayudó su comentario: en mi caso, había cambiado el nombre del ensamblado en algún momento, pero VS había dejado el Nombre del ensamblado y el espacio de nombre predeterminado en las Propiedades del proyecto como los valores anteriores – Nij

+1

Hmm. Todo lo contrario para mí. Tuve que quitar el ".dll" para la solución a construir. – kmote

+0

Puedo confirmar que @kmote tiene razón: tuve que quitar el ".dll" para que la solución se construya (y que Intellisense funcione). (.NET 4.5, VS2013, ensambles sin firmar) Comportamiento muy extraño. Esta pregunta y todas sus respuestas son excelentes para resolver problemas con este atributo aparentemente problemático. – davidbak

3

Además de todo lo anterior, cuando todo parece ser correcto, pero el amigo de montaje obstinadamente se niega a ver ninguna internos, recarga la solución o reiniciar Visual Studio puede resolver el problema.

2

respuestas anteriores con PublicKey trabajaron: (Visual Studio 2015:. Necesita estar en una línea, de lo contrario, se queja de que la referencia de ensamblado es válido o no se hace referencia PublicKeyToken no funcionaba)

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

Gracias a @ Joe

para obtener la clave pública del conjunto del amigo:

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

Dentro de un símbolo del sistema Developper (inicio> Programas> Visual Studio 2015 > Visual Studio Tools> Indicador de comando del desarrollador para VS2015). Gracias a @Ian G.

Aunque, el toque final que me hizo funcionar 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.

2

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

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

Siga los siguientes pasos para generar MSDN nueva clave pública completa para el montaje de Visual Studio.

para añadir un elemento Obtener Asamblea de clave pública 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 Agregue 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 programa (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 casilla de verificación Usar ventana de salida.

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

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

3

En mi caso usando VS.Net 2015, tuve que firmar AMBOS ensambles (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.

+0

¡Gracias! Intenté todo en VS2015. La firma de ambas asambleas lo arregló para mí. –

1

se aplica sólo si te gusta mantener asambleas sin firmar como el montaje sin firmar (y no desea firmar por varias razones):

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

PERO: Tan pronto como compile 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 compilador fallen al verificar la coincidencia de PublicKey.

Por último, es posible utilizar las asambleas sin firmar: https://msdn.microsoft.com/en-us/library/bb384966.aspx Debe asegurarse de que los dos conjuntos no están firmados y el atributo Asamblea debe ser sin información PublicKey:

<Assembly: InternalsVisibleTo("friend_unsigned_B")>

0

Otra posibilidad que puede ser complicado de rastrear, dependiendo de cómo se escribe su código.

  1. Estás invocar un método interno se define en X de otro conjunto Y
  2. La firma del método utiliza tipos internos definidos en Z
  3. A continuación, tiene que agregar [InternalsVisibleTo] en X y 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 tienes escrito como el anterior, en el que no se está refiriendo t o ZType directamente en Y, después de haber agregado Y como amigo de X, puede desconcertar por qué su código aún no se compila.

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

0

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 con el botón derecho en su proyecto y haga clic en Propiedades. Debajo de Aplicación, asegúrese de que el Nombre del ensamblaje y Espacio de nombre predeterminado es lo que espera.