2009-10-29 15 views
5

¿Es posible hacer esto transfiriendo el ensamblaje a la memoria? Si es así, ¿cómo hace uno esto?Cómo cargar un ensamblaje sin usar Assembly.Load?

Motivo:

No quiero bloquear la DLL que se carga. Quiero tener la capacidad de carga dinámica, cambiar el código, compilar y volver a cargar de nuevo

+4

¿Por qué necesitaría para hacer eso? ¿Por qué no puedes usar Assembly.Load? –

+0

No quiero bloquear el dll que está cargado. Quiero tener la capacidad de cargar dinámicamente, cambiar el código, compilar y volver a cargarlo. –

+1

Luego cambie su pregunta a preguntar eso, y responderé. –

Respuesta

11

se puede hacer por una sobrecarga de carga utilizando matriz de bytes. Es necesario leer los bytes de montaje antes de la carga y no va a bloquear el archivo:

byte[] readAllBytes = File.ReadAllBytes("path"); 
Assembly assembly = Assembly.Load(readAllBytes); 
+1

Bueno para cargar, no tan bueno para descargar/recargar. –

+0

Henk, ¿cómo quieres decir que no es bueno para descargar? Hacer esto de nuevo no reemplazará las clases cargadas existentes? –

+3

Al cargar desde bytes, carga una copia cada vez. Obtiene una nueva referencia de ensamblado en la que puede trabajar, pero no descarga la anterior. Depende de lo que realmente va a hacer con él, así que es una compensación con simplicidad. – Elisha

18

Como yo lo entiendo, que quiere hacer lo siguiente:

  1. carga un ensamblado de disco, en la memoria, para usar datos en él o llamar al código
  2. Poder descargar el conjunto más adelante
  3. Evite bloquear el ensamblaje en el disco, para que pueda modificarlo sin tener que salir de la aplicación (o descargar el montaje primero)

Básicamente, lo que está describiendo es un tipo de sistema de complemento, y puede hacerlo con el uso de dll sombreados y dominios de aplicación.

Primero, para descargar un ensamblaje, sin simplemente salir de la aplicación, debe cargar ese ensamblaje en un dominio de aplicación separado. Debería poder encontrar buenos tutoriales en la red sobre cómo hacerlo.

Aquí hay un Google query que debería proporcionarle algunos artículos iniciales.

En segundo lugar, para evitar bloquear el conjunto en el disco, es simple, simplemente haga una copia primero y cargue la copia en lugar del original. Claro, bloquearás la copia, pero la copia es solo un archivo temporal para tu aplicación, por lo que nadie debería estar interesado en modificar ese archivo de todos modos. Esto deja el archivo original desbloqueado y modificable.

Debe intentar utilizar el sombreado en lugar de utilizar las sobrecargas de Assembly.Load que pueden cargar ensamblajes de una matriz de bytes si tiene más de un ensamblaje que se cargará y reemplazará.

Por ejemplo, si su complemento A.dll se basa en un segundo conjunto B.dll, y utiliza el truco de matriz de bytes para cargar A.dll en la memoria antes de llamar a Assembly.Load, necesita manejar la resolución del conjunto llama al dominio de su aplicación (se le puede decir cada vez que se necesita cargar un ensamblaje y "ayuda" al proceso de carga), o necesita asegurarse de que B.dll se cargue primero de la misma manera que se carga A.dll; de lo contrario, cargue A.dll de la memoria cargará automáticamente B.dll del disco.


Aquí hay más información sobre el uso de dominios de aplicación separados.

Cuando se crea otro dominio de aplicación, a través del uso de la clase AppDomain en .NET, que está creando un compartimiento separado en la memoria donde se puede ejecutar código. Está realmente separado de su dominio de aplicación principal y solo tiene un pequeño orificio a través de la pared que los separa.

A través de este agujero puede pasar mensajes, como llamadas de método y datos.

Después de construir el nuevo dominio de aplicación, carga uno o más ensamblajes dentro de él. Normalmente cargará 1 si el conjunto que desea cargar ha sido creado para este tipo de carga, o 2 si no lo ha hecho (más sobre esto más abajo).

Después de cargar el conjunto, construye uno o más objetos dentro de ese otro dominio de aplicación, de forma que el primer dominio de aplicación pueda hablar con esos objetos. Estos objetos deben descender desde MarshalByRefObject, que es una clase que permite que ocurra algo de magia.

Básicamente lo que ocurre es lo siguiente. Dentro de ese otro dominio de aplicación, se crea un objeto de un tipo cargado en ese dominio de aplicación. Este tipo desciende de MarshalByRefObject. La solicitud para construir este objeto provino del primer dominio de aplicación, y dentro de este dominio de aplicación, se construye un objeto proxy, que se parece, pero no es, el mismo objeto que se creó en ese otro dominio de aplicación. El proxy habla con ese otro objeto, a través de ese agujero.

Ahora tiene dos dominios de aplicación y dos objetos, uno a cada lado, y los objetos se comunican entre sí.

Con esta configuración, más adelante puede cortar la conexión entre los objetos y luego descargar ese otro dominio de aplicación, que básicamente destruye ese compartimiento. Luego, si lo desea, puede construir un nuevo dominio de segunda aplicación y comenzar de nuevo, de hecho, volver a cargar los ensamblados desde el disco.

Una cosa a tener en cuenta es la información que se pasa por este agujero. Si alguno de los datos que pasan a través de ese agujero es un objeto que se declara en la asamblea que ha cargado (el plugin o conjunto de extensión), entonces no sólo va a conseguir ese objeto nuevo en su dominio principal de la aplicación, su dominio principal de la aplicación también cargue ese ensamblaje en su propio dominio y, por lo tanto, impida hablar correctamente con su segundo dominio de aplicación después de una recarga.

Así que asegúrese de no hacer eso, pase tipos nativos o tipos que están definidos fuera de los ensamblajes que desea reemplazar.

he mencionado que es posible que desee cargar al menos dos conjuntos. El razonamiento detrás de esto es que si el tipo que se desea construir, el tipo que se declara en ese ensamblado que desea cargar, no desciende de MarshalByRefObject, entonces surge nuevamente el problema de pasar tipos a través de ese agujero, y también cargarás el ensamblado en tu dominio principal. Una forma típica de manejar esto es tener algún tipo de plugin de clase gerente, que no descienden de MarshalByRefObject, y tienen este gerente sentarse en ese otro dominio y hacer hablar a los otros tipos. Esto evita el problema de pasar los tipos a través de ese agujero.

he estado divagando por un tiempo aquí ahora, así que dejaré que sea, pero con esta información que debería ser capaz de entender y hacer uso de los artículos encontrados a través de Google que consultar un poco más fácil.

+0

1 independiente AppDomain es el camino a seguir. –

+0

+1 realmente la única manera de lograr esto. La descarga del AppDomain "dinámico" evita la típica pérdida de memoria. –

+0

Gracias, cuando carga un ensamblado a un dominio de aplicación separado, ¿puede acceder a él desde mi aplicación? ¿Cómo ayudan los appdins? (No lo sé). ¿Esto todavía bloqueará el dll? Sin embargo, copiar el montaje todo el tiempo parece un hack sucio. –

3

Puede crear una copia temporal del ensamblaje y cargar esa copia con Assembly.Load. Coloque un monitor de archivos en el original y descargue/vuelva a cargar una copia temporal del ensamblaje actualizado cuando el monitor de archivos detecte un cambio.

1

Si compila los archivos DLL en marcha de las fuentes, que no necesariamente siquiera tiene que hacer una copia, en vez el proceso de recompilación debe ser el siguiente:

1) Destruya el dominio de la aplicación que tiene los ensamblados cargados, desbloqueando efectivamente las DLL.

2) volver a compilar los scripts.

3) Volver a crear el dominio de aplicación para los plugins, y cargar los nuevos montajes en ella.

+0

Con la desventaja de que hay un espacio de varios segundos por lo menos entre 1) y 3) donde su aplicación no está disponible. –

Cuestiones relacionadas