2009-07-21 8 views
10

En realidad, traté de implementar algún tipo de ensambles "estáticamente vinculados", dentro de mi solución. Así que he intentado lo siguiente:¿Cómo cargar el ensamblado en tiempo de ejecución antes del evento AssemblyResolve?

  • añadir una referencia a mi montaje con CopyLocal = false
  • Agregar el archivo .dll en sí a mi solución con 'Agregar enlace'
  • Agregar el archivo .dll en sí a mis recursos con 'Agregar recurso' - "Agregar archivo existente
  • Adición de algún tipo de mi conjunto en Form1 como private MyObject temp = new MyObject();

Después de estos pasos me dieron el FileNotFoundException como se esperaba. Así que intentemos cargar el ensamblado dentro del AssemblyResolveEvent con este truco rápido

AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => 
    { 
     Assembly MyAssembly = AppDomain.CurrentDomain.Load(Properties.Resources.ExternalAssembly); 
     return MyAssembly; 
    }; 

¡Esto funciona! Puedo cargar mi ensamblaje desde un archivo de recursos dentro de un AssemblyResolveEvent. Pero este evento solo ocurre, si no pudo encontrar mi ensamblaje en otro lugar. Pero ¿cómo puedo hacer que mi ensamblaje se cargue antes de .Net intenta buscar en los diferentes lugares?

Debido a los hechos de Checking for Previously Referenced Assemblies pensé que sería posible cargar el conjunto de antemano en el dominio y esto se tomaría.

yo probamos este dentro Program.cs utilizando el siguiente método principal()

static void Main() 
{ 
    LoadMyAssemblies(); 
    AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => LoadMyAssemblies(); 
    Application.EnableVisualStyles(); 
    Application.SetCompatibleTextRenderingDefault(false); 
    Application.Run(new Form1()); 
} 

private static Assembly LoadMyAssemblies() 
{ 
    Assembly result = AppDomain.CurrentDomain.Load(Properties.Resources.MyStaticAssembly); 
    return result; 
} 

Pero todavía se ejecuta en el ResolveEventHandler. Y mucho mejor, si vuelvo a cargar el ensamblado y echo un vistazo a AppDomain.CurrentDomain.GetAssemblies() ¡puedo ver que mi ensamblaje se carga dos veces!

Así que cualquier idea de por qué no se tendrá mi ensamblado cargado en cuenta cuando se carga antes del evento AssemblyResolve ?? Con la ayuda del depurador también devolví un nulo cuando la llamada vino de AssemblyResolve, pero en este caso obtuve una excepción FileNotFoundException como al principio.

Respuesta

3

En caso de que no lo sabía, hay una herramienta llamada ILMerge de Investigación MS que combina montajes en un solo archivo.

También puede crear montajes de varios archivos utilizando el Assembly Linker tool.

Plus para que responder a la pregunta original, el problema es que creo que el tiempo de ejecución no sabe que el montaje que ha cargado manualmente es el que debe estar buscando. Por lo tanto, en el evento de resolución de ensamblaje en lugar de cargar nuevamente el ensamblaje, solo devuelva la referencia al ensamblaje que ha cargado manualmente.

+0

ILMerge ya se utilizará en algunas otras situaciones, pero en este caso no es la "mejor" solución. Dar en AssemblyResolver el mismo ensamblaje tampoco es una buena solución, porque si el mismo ensamblado también se encuentra en la carpeta del programa o GAC, este se tomará y el evento no se lanzará. – Oliver

3

El cuaderno CLR no sabe que LoadMyAssemblies() hace lo mismo que el evento AssemblyResolve, y que ambos están tratando de buscar el mismo conjunto y cargarlo.

El evento AssemblyResolve siempre se dispara en el punto en que el Binder decide que ha buscado todas las ubicaciones posibles (que se pueden buscar con esa aplicación) y no ha podido encontrar una coincidencia.

Esto plantea la pregunta original, que es, ¿por qué desearía vincular estáticamente sus ensamblados administrados?Lea este tema por una gran cantidad de discusión sobre este Static linking advantages

Voy a seguir adelante y responder a la parte sobre cómo evitar golpear el evento AssemblyResolve 1) Coloque la unidad en la GAC. En lo que se refiere a Binder, el GAC siempre gana. 2) Coloque su ensamblaje en la ruta de inspección y asegúrese de que el Binder lo levanta (busque el artículo "Cómo el tiempo de ejecución localiza ensamblajes" en MSDN para obtener más información al respecto).

+0

Tiene razón, que CLR Binder no sabe nada sobre mi función. Pero como ya lo mencionó, activará el evento AssemblyResolve cuando haya buscado todas las ubicaciones posibles. ¡Pero eso no es verdad! ¡Simplemente no miró en la lista de ensamblajes cargados dentro del Dominio de aplicación actual! Pero después de leer esto (http://msdn.microsoft.com/en-us/library/aa98tba8.aspx) debería aparecer allí. – Oliver

Cuestiones relacionadas