Incrustar ensamblajes dentro de otro ensamblaje

Si crea una biblioteca de clases que usa elementos de otros ensamblajes, ¿es posible incrustar esos otros ensambles dentro de la biblioteca de clases como algún tipo de recurso?

Es decir, en lugar de tener MyAssembly.dll , SomeAssembly1.dll y SomeAssembly2.dll en el sistema de archivos, esos otros dos archivos se agrupan en MyAssembly.dll y se pueden usar en su código.


También estoy un poco confundido acerca de por qué los ensamblados .NET son archivos .dll . ¿Este formato no existía antes de .NET? ¿Todos los archivos .NET son archivos DLL, pero no todos los archivos DLL son ensamblados .NET? ¿Por qué usan el mismo formato de archivo y / o extensión de archivo?

Eche un vistazo a ILMerge para fusionar conjuntos.

También estoy un poco confundido acerca de por qué los ensamblados .NET son archivos .dll. ¿Este formato no existía antes de .NET?

Sí.

Son todas las DLL de ensamblados .NET,

Ya sea DLL o EXE normalmente, pero también puede ser netmodule.

pero no todas las DLL son ensamblados .NET?

Correcto.

¿Por qué usan el mismo formato de archivo y / o extensión de archivo?

¿Por qué debería ser diferente? ¡Tiene el mismo propósito!

ILMerge fusiona ensamblados, lo cual es bueno, pero a veces no es lo que quieres. Por ejemplo, cuando el ensamblado en cuestión es un ensamblado con un nombre fuerte, y usted no tiene la clave para él, entonces no puede hacer ILMerge sin romper esa firma. Lo que significa que tiene que implementar múltiples ensambles.

Como alternativa a ilmerge, puede incorporar uno o más ensamblados como recursos en su exe o DLL. Luego, en el tiempo de ejecución, cuando se cargan los ensamblajes, puede extraer el ensamblado incrustado programáticamente y cargarlo y ejecutarlo. Suena complicado, pero solo hay un poco de código repetitivo.

Para hacerlo, inserte un ensamblaje, tal como lo haría con cualquier otro recurso (imagen, archivo de traducción, datos, etc.). A continuación, configure un AssemblyResolver que se llame en el tiempo de ejecución. Se debe configurar en el constructor estático de la clase de inicio. El código es muy simple.

static NameOfStartupClassHere() { AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolver); } static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args) { Assembly a1 = Assembly.GetExecutingAssembly(); Stream s = a1.GetManifestResourceStream(args.Name); byte[] block = new byte[s.Length]; s.Read(block, 0, block.Length); Assembly a2 = Assembly.Load(block); return a2; } 

La propiedad Name en el parámetro ResolveEventArgs es el nombre del ensamblado que se va a resolver. Este nombre se refiere al recurso, no al nombre del archivo. Si incrusta el archivo llamado “MyAssembly.dll” y llama al recurso incrustado “Foo”, entonces el nombre que desea aquí es “Foo”. Pero eso sería confuso, entonces sugiero usar el nombre de archivo del ensamblado para el nombre del recurso. Si ha incrustado y nombrado su ensamblaje correctamente, puede simplemente llamar a GetManifestResourceStream () con el nombre del ensamblado y cargar el ensamblaje de esa manera. Muy simple.

Esto funciona con varios ensambles, tan bien como con un solo ensamblado integrado.

En una aplicación real, vas a querer un mejor manejo de errores en esa rutina, como qué pasa si no hay una transmisión por el nombre de stack. ¿Qué sucede si falla la lectura? etc. Pero eso te queda por hacer.

En el rest del código de la aplicación, utiliza tipos del ensamblaje de forma normal.

Cuando crea la aplicación, necesita agregar una referencia al ensamble en cuestión, como lo haría normalmente. Si usa las herramientas de línea de comandos, use la opción / r en csc.exe; si usa Visual Studio, deberá “Agregar referencia …” en el menú emergente del proyecto.

En tiempo de ejecución, la verificación y verificación de la versión del ensamblaje funciona como siempre.

La única diferencia está en la distribución. Cuando despliega o distribuye su aplicación, no necesita distribuir la DLL para el ensamblado integrado (y referenciado). Simplemente despliega el ensamblaje principal; no es necesario distribuir los otros ensamblajes porque están integrados en el DLL o EXE principal.

Puede insertar un ensamblaje (o cualquier archivo, en realidad) como recurso (y luego usar la clase ResourceManager para acceder a ellos), pero si solo quiere combinar ensamblajes, es mejor que utilice una herramienta como ILMerge .

Los archivos EXE y DLL son ejecutables portátiles de Windows , que son generics para acomodar futuros tipos de código, incluido cualquier código .NET (también se pueden ejecutar en DOS pero solo muestran un mensaje que dice que no se deben ejecutar en DOS). Incluyen instrucciones para iniciar el tiempo de ejecución .NET si aún no se está ejecutando. También es posible que un solo ensamblaje abarque múltiples archivos, aunque esto casi nunca ocurre.

Tenga en cuenta que ILMerge no funciona con recursos incrustados como XAML, por lo que las aplicaciones WPF, etc. necesitarán usar el método de Cheeso.

También está la utilidad mkbundle que ofrece el proyecto Mono

¿Por qué usan el mismo formato de archivo y / o extensión de archivo?

¿Por qué debería ser diferente? ¡Tiene el mismo propósito!

Mi 2 ¢ bit de aclaración aquí: DLL es Dynamic Link Library. Tanto el .dll de estilo antiguo (código C) como el .dll de estilo .net son, por definición, bibliotecas de “enlace dynamic”. Entonces .dll es una descripción adecuada para ambos.

Con respecto a la respuesta de Cheeso de integrar los ensamblados como recursos y cargarlos dinámicamente utilizando la sobrecarga de Carga (byte []) usando un manejador de eventos AssemblyResolve, necesita modificar el resolver para verificar que el AppDomain tenga una instancia existente del Assembly para cargar y devolver la instancia de ensamblaje existente si ya está cargada.

Los ensamblados cargados con esa sobrecarga no tienen contexto, lo que puede hacer que el marco intente y vuelva a cargar el ensamblaje varias veces. Sin devolver una instancia ya cargada, puede terminar con varias instancias del mismo código de ensamblado y tipos que deberían ser iguales pero no lo serán, porque el marco considera que provienen de dos ensamblajes diferentes.

Al menos una forma en que se realizarán múltiples eventos de AssemblyResolve para el mismo conjunto cargado en el “Sin contexto” es cuando tiene referencias a tipos que expone desde ensamblajes múltiples cargados en su AppDomain, a medida que se ejecuta el código que necesita esos tipos resueltos.

https://msdn.microsoft.com/en-us/library/dd153782%28v=vs.110%29.aspx

Un par de puntos destacados del enlace:

“Otros ensamblados no se pueden unir a ensamblados que se cargan sin contexto, a menos que maneje el evento AppDomain.AssemblyResolve”

“Cargar ensamblajes múltiples con la misma identidad sin contexto puede causar problemas de identidad de tipo similares a los causados ​​al cargar ensamblajes con la misma identidad en contextos múltiples. Consulte Evitar cargar un ensamblaje en contextos múltiples.”