2011-08-07 25 views
5

Estoy haciendo un programa en función de algunos archivos DLL incluidos en un programa de terceros. No puedo distribuir estos archivos DLL por mi cuenta. El programa de terceros debe estar instalado para que mi programa funcione..NET dll de referencia desde otra ubicación

¿Cómo puedo hacer una referencia a estos archivos DLL? Sé la ubicación exacta de ellos a través de una clave de registro establecida por el programa.

He intentado agregar los archivos en Proyecto-> Referencias y establezco CopyLocal en falso, pero cuando comienzo, obtengo una excepción FileNotFoundException "No se pudo cargar el archivo o el ensamblaje".

He intentado agregar un evento a AppDomain.CurrentDomain.AssemblyResolve y cargar los archivos allí, pero el problema es que recibo la excepción incluso antes de que mi programa comience. Incluso si pongo un punto de interrupción en la primera línea, se lanzará la excepción antes de que se llegue al punto de interrupción.

+0

En general, los proveedores de terceros explican cómo utilizar sus componentes en producción si no siguen la práctica estándar (que parece ser el caso aquí). ¿No tienes una documentación decente? –

+0

Como dice simon, generalmente hay un acuerdo distribuible con asambleas de terceros, o si son fuertes, ¿los incluyó en el GAC? –

+0

¿Se suscribe al evento 'AssemblyResolve' lo antes posible? Si no se suscribe lo suficientemente pronto, se puede ejecutar algún código que dependa de su ensamblado de terceros antes de poder resolverlo. –

Respuesta

9

De C# 3.0 in a Nutshell, 3rd edition, by Joseph and Ben Albahari, p. 557-558:

Asambleas Distribución fuera de la carpeta Base

A veces es posible elegir para implementar ensamblados a lugares que no sean el directorio base de la aplicación [...] Para hacer esto trabajo, debe ayudar al CLR a encontrar los ensamblajes fuera de la carpeta base. La solución más fácil es manejar el evento AssemblyResolve.

(Podemos ignorar el hecho de que, en su caso, alguien que no se está desplegando las asambleas.)

que ha intentado. Pero una pista muy importante sigue algo más tarde. Leer los dos comentarios de código:

public static void Loader 
{ 
    static void Main(string[] args) 
    { 
     AppDomain.CurrentDomain.AssemblyResolve += FindAssem; 

     // We must switch to another class before attempting to use 
     // any of the types in C:\ExtraAssemblies: 
     Program.Go(); 
    } 

    static Assembly FindAssem(object sender, ResolveEventArgs args) 
    { 
     string simpleName = new AssemblyName(args.Name).Name; 
     string path = @"C:\ExtraAssemblies\" + simpleName + ".dll"; 

     if (!File.Exists(path)) return null; 
     return Assembly.LoadFrom(path); 
    } 
} 

public class Program 
{ 
    public static void Go() 
    { 
     // Now we can reference types defined in C:\ExtraAssemblies 
    } 
} 

Como se ve, la clase en la que resuelva los montajes externos no debe referirse a cualquier tipo de cualquiera de los archivos DLL externa en cualquier lugar. Si lo hiciera, la ejecución del código se detendría antes de que su AssemblyResolve tenga la oportunidad de ejecutarse.

+0

Bingo! Mover el uso de los elementos a los que se hace referencia en otra clase distinta de la que tiene Main() lo resolvió. Gracias :) – aero

+0

P.S .: Debo admitir que no sé si esta solución está oficialmente documentada, o si es solo un truco ingenioso que funciona con algunas versiones de frameworks, pero puede fallar con otros. Por lo tanto, estoy totalmente de acuerdo con la declaración final de Hans Passant: debería haber una manera más fácil. – stakx

+0

¡Esto es genial, gracias! Preguntas: si FindAssem() devuelve nulo, ¿cómo evito que Go() no lance FileNotFoundException? – Eddie

4

Tu aplicación es una bomba porque el compilador JIT es el primero que necesita cargar el conjunto. Deberá evitar cuidadosamente usar tipos del ensamblado en su método Main(). Eso no es difícil de hacer, simplemente escriba otro método principal y asígnele un atributo que le indique a la trepidación que nunca debe alinear ese método. Sin el atributo, aún puede bombardear en la versión Release cuando el optimizador indique el método. De esta manera:

using System; 
using System.Runtime.CompilerServices; 

class Program { 
    static void Main(string[] args) { 
     AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); 
     DelayedMain(args); 
    } 

    [MethodImpl(MethodImplOptions.NoInlining)] 
    static void DelayedMain(string[] args) { 
     // etc.. 
    } 


    static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { 
     // etc... 
    } 
} 

Antes de comprometerse a hacerlo de esta manera, póngase en contacto con el proveedor y solicite recomendaciones. Tiene que haber una manera más fácil de ejercer sus derechos de licencia. El GAC sería una opción común, quizás solo necesites ejecutar gacutil en tu máquina de desarrollo.

Cuestiones relacionadas