2009-02-02 10 views
32

¿Es posible ejecutar algún código cuando se carga un ensamblaje, sin hacer nada específico en el código de carga? Lo que estoy buscando es como un constructor estático en un tipo..Net: código de ejecución cuando se carga el ensamblaje

Ej:

Asamblea Una no sabe nada de la Asamblea B, pero B no sabe de A. Asamblea A necesita saber ciertas cosas sobre B si se carga B. Cuando el ensamblado B es cargado por el tiempo de ejecución (referenciado o explícito), quiero que se ejecute un trozo de código (método estático o atributo) que invoque un método en la Asamblea A.

Se desconoce la causa raíz de este problema tipos que se encuentran al serializar un tipo en A que contiene tipos de B no conocidos en tiempo de compilación como interfaces.

Respuesta

37

El CLR apoya module initializers. Tendría que hackear el código de C++/CLI o ilasm.exe para usarlos.

+9

No es necesario hackear con https://github.com/Fody/ModuleInit –

+2

@RichardCollette todavía está haciendo el truco, pero Fody solo está automatizando el truco en el proceso de compilación para hacerlo más fácil. –

6

(edición - se aplica a C#, por un enfoque C++, consulte this answer)

Básicamente, no: no se puede. Esta sería una gran superficie de ataque, y no está permitida. Es posible que desee colocar un controlador estático en algunos de los tipos B que garanticen la ejecución del código de inicio, pero eso es todo ...

+5

¿Por qué es una superficie de ataque? –

+1

Parece que sería bastante fácil ocultar código allí que ningún código invoca a sabiendas - difícil de rastrear, etc. No digamos la cuestión de qué hilo debe ejecutarlo ... Tal vez no puedo vocalizarlo correctamente, pero me parece imprudente. Pero es discutible, ya que no puede hacerlo de todos modos ;-p –

+0

¿Sabe usted si hay información sobre él (los inicializadores de módulos no se ejecutan en Load, sino en constructores estáticos), por lo que es interesante si el código puede ejecutar durante la carga en sí. Si desea comprobar si puede responder también esta pregunta muy cercana: http://stackoverflow.com/questions/24718917/can-a-call-to-assembly-loadbyte-raise-the-appdomain-assemblyresolve-event/24719526? noredirect = 1 # comment38423553_24719526 –

3

Probablemente deba volver a utilizar su enfoque de serialización para mitigar este problema. Si serializa utilizando ISerializable y el atributo SerializableAttribute, puede hacerlo de tal manera que el gráfico de serialización se carga el ensamblado B cuando sea necesario sin montaje Una vez tener que conocer de manera explícita sobre el montaje B.

+0

¿Cómo puedo identificar y cargar el ensamblaje B utilizando este método? –

+0

Si usa serializar, digamos un BinaryFormatter, cualquier tipo en su gráfico de serialización que implemente ISerializable tendrá sus constructores llamados durante el deserialize, en el que puede llamar al código que necesite. Como, al serializar, las consultas de serialización para la interfaz ... –

+0

... no importa si A solo hace referencia a los tipos B por una interfaz, se serializarán correctamente. –

5

Puede usar constructores estáticos en .Net, pero desafortunadamente no hacen lo que usted desea. Los constructores estáticos solo se ejecutan justo antes de que se use un tipo. Ver http://msdn.microsoft.com/en-us/library/k9x6w0hc(VS.80).aspx para más detalles.

Es posible que obtenga un poco de millaje al suscribirse al evento AssemblyLoad de su AppDomain. Ver http://msdn.microsoft.com/en-us/library/system.appdomain.assemblyload.aspx.

En su controlador de eventos puede reflexionar sobre el ensamblaje recién cargado y hacer que ejecute el código que desee.

+0

Desafortunadamente, ya que solo uno de los 30 ensambles extraños necesita este registro hecho, AssemblyLoad puede ser un poco excesivo. –

0

Al usar un ensamblaje mixto, puede hacer que DllMain funcione en una carga de ensamblaje.

3

Hay 3 opciones para inicializar un ensamblado .NET:

  1. se escribe una función estática Init() o Main() en su Asamblea que ser inicializado y llamar a esta función mediante la reflexión a partir del código C# que carga esta Asamblea.
  2. Escriba un conjunto de C++ administrado donde coloca su código en DllMain(). Tenga cuidado porque su código se ejecutará en el bloqueo del cargador, donde están prohibidas varias cosas (como cargar otras DLL, ...). Pero puede iniciar un nuevo hilo que CUALQUIER elemento de inicialización. (Sobre LoaderLock: https://msdn.microsoft.com/en-us/library/ms173266.aspx) (Sobre DllMain: C# to C++/CLI to C DLL System.IO.FileNotFoundException)
  3. compila un C de la Asamblea puro # y modificar el archivo DLL compilado a añadir un código módulo de inicialización como se explica aquí: http://einaregilsson.com/module-initializers-in-csharp/ La desventaja de este método es que el la función de inicialización no se invoca inmediatamente cuando el ensamblaje se carga en el proceso. Pero se llama antes de acceder a cualquier otra cosa en el ensamblado.
+0

1) podría decirse que no satisface _ "sin hacer nada específico en el código de carga?" _ – MickyD

+0

La única forma de no modificar el código de carga es la opción 2.) – Elmue

+0

Sí, me gusta bastante su opción 2 – MickyD

Cuestiones relacionadas