2011-03-10 18 views
7

Estoy desarrollando una aplicación que hace referencia y usa ensamblajes de terceros de un determinado Proveedor; en el cuadro de desarrollo tengo estos 3 ensamblajes en una carpeta de referencia en mi árbol de fuentes y puedo hacer referencia a ellos y crear la aplicación, las compilaciones de aplicaciones pero no se ejecutan porque la aplicación de servidor completa no está instalada, pero esto está bien.Resolver referencias de ensamblados desde otra carpeta

En el servidor donde quiero copiar esta aplicación personalizada y ejecutar todos los conjuntos que estoy referenciación están en carpeta algo como:

D:\ProgramFiles\VendorName\ProductName\Support\API\Bin64 

y si copio mi pequeño ejecutable en esa carpeta y ejecutarlo, se funciona perfectamente, pero si pongo mi .exe en una carpeta más apropiado como yo quiero:

D:\ProgramFiles\MyCompanyName\MyProduct\bin\... 

no funciona porque no puede resolver esas asambleas.

Sé que puedo usar sondeos en app.config para especificar en qué carpetas mi exe tiene que buscar referencias, pero imy caso los conjuntos no están en una subcarpeta, más en una ubicación completamente diferente.

No quiero copiar todos los ensamblados de proveedores en la carpeta de mi aplicación y no puedo poner solo los 3 a los que me refiero porque también están cargando otros ensamblajes y a menos que los tenga todos (muchos ...) , No funciona.

No estoy haciendo nada especial, no creando dominios de aplicaciones y no cargando ensambles por reflexión, solo quiero que CLR resuelva las referencias según sean necesarias en el inicio o la ejecución de la aplicación.

Gracias.

Editar: aquí el código de trabajo final

static System.Reflection.Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 
{ 
    Logger logger = new Logger(); 

    try 
    { 
     string RMSAssemblyFolder = ConfigurationManager.AppSettings["RMSAssemblyFolder"]; 

     Assembly MyAssembly = null; 
     string strTempAssmbPath = string.Empty; 

     Assembly objExecutingAssemblies = Assembly.GetExecutingAssembly(); 
     AssemblyName[] arrReferencedAssmbNames = objExecutingAssemblies.GetReferencedAssemblies(); 

     AssemblyName myAssemblyName = Array.Find<AssemblyName>(arrReferencedAssmbNames, a => a.Name == args.Name); 

     if (myAssemblyName != null) 
     { 
      MyAssembly = Assembly.LoadFrom(myAssemblyName.CodeBase); 
     } 
     else 
     { 
      strTempAssmbPath = Path.Combine(RMSAssemblyFolder, args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll"); 

      if (!string.IsNullOrEmpty(strTempAssmbPath)) 
      { 
       if (File.Exists(strTempAssmbPath)) 
       { 
        logger.Information("Assembly to load: {0} - File was found in: {1}", args.Name, strTempAssmbPath); 

        // Loads the assembly from the specified path.     
        MyAssembly = Assembly.LoadFrom(strTempAssmbPath); 
       } 
      } 
     } 

     // Returns the loaded assembly. 
     return MyAssembly; 
    } 
    catch (Exception exc) 
    { 
     logger.Error(exc); 
     return null; 
    } 
} 
+0

posible duplicado de http://stackoverflow.com/questions/1373100/how-to-add-folder-to-assembly-search-path-at-runtime-in-net – nawfal

Respuesta

12

primer lugar, debe encontrar la carpeta en la tesis DLL se instalan a continuación, utilizar AppDomain.AssemblyResolve para enganchar resolución de la Asamblea y tratar de cargar las asambleas solicitadas a esta carpeta.

Se verá algo como esto (no probado, y hay que comprobar lo args.Name contienen exactamente, podría contener la versión y el nombre seguro junto con el nombre de tipo):

var otherCompanyDlls = new DirectoryInfo(companyFolder).GetFiles("*.dll"); 

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => 
{ 
    var dll = otherCompanyDlls.FirstOrDefault(fi => fi.Name == args.Name); 
    if (dll == null) 
    { 
     return null; 
    } 

    return Assembly.Load(dll.FullName); 
}; 
+0

Gracias, lo he solucionado usando tu idea y mi código en el edi ted pregunta y ahora funciona bien :) –

+0

Seguramente mi solución puede optimizarse, no estoy seguro de si este método tiene que devolver nulo si no se encuentra un ensamblado en la carpeta personalizada y si es así, el CLR aún lo buscará en el GAC, porque, por ejemplo, he notado que este método también es necesario para ensamblajes como System.XML.Serializer ...Estoy probando esto en una aplicación de consola que aloja un servicio WCF vinculado a netTcp, ahora funciona y puedo ejecutar la aplicación desde cualquier carpeta, al final crearé un servicio Windows para alojar mi WCF. Gracias de nuevo.)) –

+0

Coo, gracias. Intentaremos esto en unos días. – Tarion

0

Uso SN.exe: SN -T VendorAssembly.dll, esto devolverá un número hexadecimal que es el símbolo de clave pública y, a continuación, hacer referencia al ensamblado de aplicación .config. Para obtener la versión, haga clic con el botón derecho en el ensamblado de su proveedor y utilícela para el valor de la versión codeBase, href = ruta que mencionó.

<configuration> 
     <runtime> 
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 
      <dependentAssembly> 
       <assemblyIdentity name="VendorAssembly" culture="neutral" publicKeyToken="307041694a995978"/> 
       <codeBase version="1.1.1.1" href="FILE://D:/ProgramFiles/VendorName/ProductName/Support/API/Bin64/VendorAssembly.dll"/> 
      </dependentAssembly> 
      </assemblyBinding> 
     </runtime> 
    </configuration> 
+0

Hola, desearía que funcionara, aún recibo la excepción FileNotFound ... el ensamblado Necesito referencia no es fuertemente nombrado, supongo, SN -t no funcionó, pero vi el PublicKeyToken del mensaje de excepción, así que copié su valor desde allí, todavía no se puede resolver ... :( –

Cuestiones relacionadas