Mis archivos DLL son cargados por una aplicación de terceros, que no podemos personalizar. Mis ensamblajes deben estar ubicados en su propia carpeta. No puedo ponerlos en GAC (mi aplicación tiene un requisito para implementarse usando XCOPY). Cuando la DLL raíz intenta cargar el recurso o escribir desde otra DLL (en la misma carpeta), la carga falla (FileNotFound). ¿Es posible agregar la carpeta donde se encuentran mis archivos DLL a la ruta de búsqueda de ensamblados mediante programación (desde la DLL de raíz)? No tengo permiso para cambiar los archivos de configuración de la aplicación.¿Cómo agregar carpeta a la ruta de búsqueda del ensamblado en el tiempo de ejecución en .NET?
Respuesta
Puede agregar probing path al archivo .config de su aplicación, pero solo funcionará si la ruta de exploración está contenida en el directorio base de su aplicación.
Parece que podría utilizar el evento AppDomain.AssemblyResolve y cargar manualmente las dependencias de su directorio DLL.
Editar (desde el comentario):
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(LoadFromSameFolder);
static Assembly LoadFromSameFolder(object sender, ResolveEventArgs args)
{
string folderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string assemblyPath = Path.Combine(folderPath, new AssemblyName(args.Name).Name + ".dll");
if (!File.Exists(assemblyPath)) return null;
Assembly assembly = Assembly.LoadFrom(assemblyPath);
return assembly;
}
¡Gracias, Mattias! Esto funciona: AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.AssemblyResolve + = new ResolveEventHandler (LoadFromSameFolderResolveEventHandler); Asamblea estática LoadFromSameFolderResolveEventHandler (remitente del objeto, ResolveEventArgs args) { string folderPath = Path.GetDirectoryName (Assembly.GetExecutingAssembly(). Location); string assemblyPath = Path.Combine (folderPath, args.Name + ".dll"); Ensamblaje de ensamblaje = Assembly.LoadFrom (assemblyPath); conjunto de retorno; } – isobretatel
¡Gran solución! Aquí hay un artículo que describe algunas otras soluciones, incluida esta en detalle: http://kbalertz.com/897297/consume-assemblies-located-folder-different-application-folder-Visual-Basic.aspx (warning: its for VB , no C# y un poco viejo) – Domenic
¿Qué harías si quisieras "retroceder" al Resolver básico? p.ej. 'if (! File.Exists (asmPath)) return searchInGAC (...);' –
mirada en AppDomain.AppendPrivatePath (en desuso) o AppDomainSetup.PrivateBinPath
Desde [MSDN] (http://msdn.microsoft.com/en-us/library/system.appdomainsetup.aspx): Cambiando las propiedades de una instancia de AppDomainSetup no afectan a ningún dominio de aplicación existente. Solo puede afectar la creación de un nuevo dominio de aplicación cuando se llama al método CreateDomain con la instancia de AppDomainSetup como parámetro. – Nathan
['AppDomain.AppendPrivatePath'] (https://msdn.microsoft.com/en-us/library/system.appdomain.appendprivatepath%28v=vs.110%29.aspx) la documentación parece sugerir que debería soporte para expandir dinámicamente la ruta de búsqueda de 'AppDomain', solo que la característica está en desuso. Si funciona, es una solución mucho más limpia que sobrecargar 'AssemblyResolve'. – binki
La mejor explicación from MS itself:
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);
private Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{
//This handler is called only when the common language runtime tries to bind to the assembly and fails.
//Retrieve the list of referenced assemblies in an array of AssemblyName.
Assembly MyAssembly, objExecutingAssembly;
string strTempAssmbPath = "";
objExecutingAssembly = Assembly.GetExecutingAssembly();
AssemblyName[] arrReferencedAssmbNames = objExecutingAssembly.GetReferencedAssemblies();
//Loop through the array of referenced assembly names.
foreach(AssemblyName strAssmbName in arrReferencedAssmbNames)
{
//Check for the assembly names that have raised the "AssemblyResolve" event.
if(strAssmbName.FullName.Substring(0, strAssmbName.FullName.IndexOf(",")) == args.Name.Substring(0, args.Name.IndexOf(",")))
{
//Build the path of the assembly from where it has to be loaded.
strTempAssmbPath = "C:\\Myassemblies\\" + args.Name.Substring(0,args.Name.IndexOf(","))+".dll";
break;
}
}
//Load the assembly from the specified path.
MyAssembly = Assembly.LoadFrom(strTempAssmbPath);
//Return the loaded assembly.
return MyAssembly;
}
'AssemblyResolve' es para CurrentDomain, no es válido para otro dominio' AppDomain.CreateDomain' – Kiquenet
Actualización para Framework 4
Dado que Framework 4 levanta el ensamblaje Evento yResolve también para recursos, en realidad este manejador funciona mejor. Se basa en el concepto de que las localizaciones se encuentran en los subdirectorios de la aplicación (uno para la localización con el nombre de la cultura, es decir, C: \ MyApp \ it para italiano) Dentro hay un archivo de recursos. El controlador también funciona si la localización es país-región, es decir it-IT o pt-BR. En este caso, el controlador "podría llamarse varias veces: una vez para cada cultura en la cadena alternativa" [de MSDN]. Esto significa que si devolvemos el valor nulo para el archivo de recursos "IT-IT", el marco plantea el evento que solicita el "it".
gancho Evento
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(currentDomain_AssemblyResolve);
Controlador de eventos
Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
//This handler is called only when the common language runtime tries to bind to the assembly and fails.
Assembly executingAssembly = Assembly.GetExecutingAssembly();
string applicationDirectory = Path.GetDirectoryName(executingAssembly.Location);
string[] fields = args.Name.Split(',');
string assemblyName = fields[0];
string assemblyCulture;
if (fields.Length < 2)
assemblyCulture = null;
else
assemblyCulture = fields[2].Substring(fields[2].IndexOf('=') + 1);
string assemblyFileName = assemblyName + ".dll";
string assemblyPath;
if (assemblyName.EndsWith(".resources"))
{
// Specific resources are located in app subdirectories
string resourceDirectory = Path.Combine(applicationDirectory, assemblyCulture);
assemblyPath = Path.Combine(resourceDirectory, assemblyFileName);
}
else
{
assemblyPath = Path.Combine(applicationDirectory, assemblyFileName);
}
if (File.Exists(assemblyPath))
{
//Load the assembly from the specified path.
Assembly loadingAssembly = Assembly.LoadFrom(assemblyPath);
//Return the loaded assembly.
return loadingAssembly;
}
else
{
return null;
}
}
Para los usuarios de C++/CLI, aquí es la respuesta @Mattias S'(que funciona para mí):
using namespace System;
using namespace System::IO;
using namespace System::Reflection;
static Assembly ^LoadFromSameFolder(Object ^sender, ResolveEventArgs ^args)
{
String ^folderPath = Path::GetDirectoryName(Assembly::GetExecutingAssembly()->Location);
String ^assemblyPath = Path::Combine(folderPath, (gcnew AssemblyName(args->Name))->Name + ".dll");
if (File::Exists(assemblyPath) == false) return nullptr;
Assembly ^assembly = Assembly::LoadFrom(assemblyPath);
return assembly;
}
// put this somewhere you know it will run (early, when the DLL gets loaded)
System::AppDomain ^currentDomain = AppDomain::CurrentDomain;
currentDomain->AssemblyResolve += gcnew ResolveEventHandler(LoadFromSameFolder);
I usé la solución @Mattias S '. Si realmente desea resolver dependencias de la misma carpeta, intente utilizar Solicitud de ensamblaje ubicación, como se muestra a continuación. args.RequestingAssembly se debe comprobar la nulidad.
System.AppDomain.CurrentDomain.AssemblyResolve += (s, args) =>
{
var loadedAssembly = System.AppDomain.CurrentDomain.GetAssemblies().Where(a => a.FullName == args.Name).FirstOrDefault();
if(loadedAssembly != null)
{
return loadedAssembly;
}
if (args.RequestingAssembly == null) return null;
string folderPath = Path.GetDirectoryName(args.RequestingAssembly.Location);
string rawAssemblyPath = Path.Combine(folderPath, new System.Reflection.AssemblyName(args.Name).Name);
string assemblyPath = rawAssemblyPath + ".dll";
if (!File.Exists(assemblyPath))
{
assemblyPath = rawAssemblyPath + ".exe";
if (!File.Exists(assemblyPath)) return null;
}
var assembly = System.Reflection.Assembly.LoadFrom(assemblyPath);
return assembly;
};
- 1. ¿Es posible agregar ruta en tiempo de ejecución en MVC3?
- 2. ¿Cómo cargar el ensamblado en tiempo de ejecución antes del evento AssemblyResolve?
- 3. Agregar imagen en tiempo de ejecución
- 4. Generación de ensamblado de DLL dinámicamente en tiempo de ejecución
- 5. ¿Se puede agregar un directorio a la ruta de clase en tiempo de ejecución?
- 6. Agregar carpeta a la ruta de Python permanentemente
- 7. Obtenga el valor AssemblyInformationalVersion del ensamblado .NET
- 8. Agregar miembros a un objeto dinámico en tiempo de ejecución
- 9. Agregar archivos a Java classpath en el tiempo de ejecución
- 10. ¿Cómo agregar margen a un botón en tiempo de ejecución?
- 11. Agregar elementos a RibbonDropDown en tiempo de ejecución
- 12. Error de tiempo de ejecución vinculante en VB6 al crear un objeto desde un ensamblado .NET
- 13. ASP.NET ¿Cómo agregar el ensamblado en web.config?
- 14. ¿Cómo puedo agregar una ruta (s) a la orden de búsqueda de DLL
- 15. Prioridades de carga del ensamblado .NET
- 16. Error: Este ensamblado está creado por un tiempo de ejecución más reciente que el tiempo de ejecución actualmente cargado.
- 17. ¿Cómo usar layoutinflator para agregar vistas en tiempo de ejecución?
- 18. Agregar DLL mediante programación en el tiempo de ejecución
- 19. ¿Cómo recupero la ruta a mi dylib en tiempo de ejecución?
- 20. agregar una ruta de búsqueda DLL personalizada @ aplicación de inicio
- 21. La mejor práctica para agregar controles en tiempo de ejecución
- 22. ¿Es posible que JIT inline inserte mi código en algún código de ensamblado en tiempo de ejecución de .NET?
- 23. Cómo agregar una ruta de DLL de tiempo de ejecución en el proyecto VIsual C++ Express 2010?
- 24. ¿Cuál es la mejor forma de obtener la ruta del ejecutable durante el tiempo de ejecución?
- 25. ¿Cómo obtener la ruta real de la aplicación Java en tiempo de ejecución?
- 26. cómo obtener entrada del usuario en el tiempo de ejecución
- 27. ¿cómo podemos eliminar un archivo de la carpeta de activos en tiempo de ejecución en android?
- 28. Cómo agregar un UIButton en tiempo de ejecución
- 29. Cómo medir el tiempo de ejecución de los comandos de ensamblado x86 y x86-64 en los ciclos del procesador?
- 30. Obtener la ejecución del nombre del ensamblado usando la reflexión
Gracias por agregar esto. He visto la solución 'AssemblyResolve' muchas veces, es bueno tener otra (y más fácil) opción. –