Las DLL no administradas no se pueden cargar en el servidor ASP.NET
iis-6 unmanaged (11)
Esta pregunta se relaciona con un sitio web ASP.NET, desarrollado originalmente en VS 2005 y ahora en VS 2008.
Este sitio web utiliza dos DLL externas no administradas que no son .NET y no tengo el código fuente para compilarlas y tengo que usarlas tal cual.
Este sitio web funciona bien desde Visual Studio, localizando y accediendo a estos archivos DLL externos correctamente. Sin embargo, cuando el sitio web se publica en un servidor web (ejecutando IIS6 y ASP.NET 2.0) en lugar de la PC de desarrollo, no puede localizar y acceder a estos archivos DLL externos, y me aparece el siguiente error:
Unable to load DLL ''XYZ.dll'': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
Las DLL externas se encuentran en el directorio bin del sitio web, junto con las DLL administradas que las envuelven y todas las otras DLL para el sitio web.
La búsqueda de este problema revela que muchas otras personas parecen tener el mismo problema al acceder a archivos DLL externos que no son de .NET desde sitios web ASP.NET, pero no he encontrado una solución que funcione.
He probado lo siguiente:
- Ejecutar DEPENDS para verificar las dependencias y establecer que las tres primeras están en el directorio System32 en la ruta, la última está en el marco .NET 2.
- Puse los dos DLL y sus dependencias en System32 y reinicié el servidor, pero el sitio web aún no podía cargar estos archivos DLL externos.
- Dio todos los derechos a ASPNET, IIS_WPG e IUSR (para ese servidor) al directorio bin del sitio web y se reinició, pero el sitio web aún no pudo cargar estos archivos DLL externos.
- Se agregaron los archivos DLL externos como elementos existentes a los proyectos y se estableció su propiedad "Copiar en salida" a "Copiar siempre", y el sitio web aún no puede encontrar los archivos DLL.
- También establezca su propiedad "Build Action" en "Embedded resource" y el sitio web aún no puede encontrar los archivos DLL.
¡Cualquier ayuda con este problema sería muy apreciada!
Añadiendo a la respuesta de Matt, esto es lo que finalmente funcionó para mí para el servidor 2003 / IIS 6 de 64 bits:
- asegúrese de que su dlls / asp.net tenga la misma versión (32/64 bit)
- Coloque los dlls no administrados en inetsrv dir (tenga en cuenta que en las ventanas de 64 bits, esto se encuentra en syswow64, aunque se haya creado el directorio sys32 / inetsrv)
- Deje los dlls gestionados en / bin
- Asegúrate de que ambos conjuntos de dll tengan permisos de lectura / ejecución
Como alternativa a poner el dll en una carpeta que ya está en la ruta (como system32) puede cambiar el valor de ruta en su proceso utilizando el siguiente código
System.Environment.SetEnvironmentVariable("Path", searchPath + ";" + oldPath)
Luego, cuando LoadLibrary intente encontrar la DLL no administrada, también escaneará searchPath. Esto puede ser preferible a hacer un lío en System32 u otras carpetas.
Después de luchar todo el día sobre este problema y finalmente encontré una solución que me conviene. Es solo una prueba, pero el método está funcionando.
namespace TestDetNet
{
static class NativeMethods
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
public partial class _Default : System.Web.UI.Page
{
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate int GetRandom();
protected System.Web.UI.WebControls.Label Label1;
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = "Hell''ou";
Label1.Font.Italic = true;
}
protected void Button1_Click(object sender, EventArgs e)
{
if (File.Exists(System.Web.HttpContext.Current.Server.MapPath("html/bin")+"//DelphiLibrary.dll")) {
IntPtr pDll = NativeMethods.LoadLibrary(System.Web.HttpContext.Current.Server.MapPath("html/bin")+"//DelphiLibrary.dll");
if (pDll == IntPtr.Zero) { Label1.Text = "pDll is zero"; }
else
{
IntPtr pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "GetRandom");
if (pAddressOfFunctionToCall == IntPtr.Zero) { Label1.Text += "IntPtr is zero"; }
else
{
GetRandom _getRandom = (GetRandom)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall,typeof(GetRandom));
int theResult = _getRandom();
bool result = NativeMethods.FreeLibrary(pDll);
Label1.Text = theResult.ToString();
}
}
}
}
}
}
Ejecute DEPENDS en XYZ.dll directamente, en la ubicación en la que lo haya implementado. Si eso no revela que falta algo, use la herramienta fuslogvw en la plataforma SDK para rastrear los errores del cargador. Además, los registros de eventos a veces contienen información sobre errores al cargar archivos DLL.
En Application_start usa esto: (personalizar / bin / x64 y carpetas bin / dll / x64 según sea necesario)
String _path = String.Concat(System.Environment.GetEnvironmentVariable("PATH")
,";"
, System.Web.Hosting.HostingEnvironment.MapPath("~/bin/x64")
,";"
, System.Web.Hosting.HostingEnvironment.MapPath("~/bin/dll/x64")
,";"
);
System.Environment.SetEnvironmentVariable("PATH", _path, EnvironmentVariableTarget.Process);
Esto sucede porque los dlls gestionados se copian en una ubicación temporal en el directorio .NET Framework. Consulte http://msdn.microsoft.com/en-us/library/ms366723.aspx para obtener detalles.
Desafortunadamente, los archivos DLL no administrados NO se copian y el proceso ASP.NET no podrá encontrarlos cuando deba cargarlos.
Una solución fácil es colocar los dlls no administrados en un directorio que está en la ruta del sistema (escriba "ruta" en la línea de comando para ver la ruta en su máquina) para que puedan ser encontrados por el proceso ASP.NET. El directorio System32 siempre está en la ruta, por lo que poner los dlls no administrados allí siempre funciona, pero recomendaría agregar alguna otra carpeta a la ruta y luego agregar los dlls allí para evitar contaminar el directorio de System32. Una gran desventaja de este método es que debe cambiar el nombre de los dlls no administrados para cada versión de su aplicación y rápidamente puede tener su propio infierno de dll.
Intente poner los dlls en el directorio / System32 / Inetsrv. Este es el directorio de trabajo de IIS en Windows Server.
Si esto no funciona intente poner los dlls en el directorio System32 y los archivos de dependencia en el directorio Inetsrv.
Me he encontrado con el mismo problema. Y probé todas las opciones anteriores, copiando a system32, inetpub, setting path environment, etc. nada funcionó. Este problema finalmente se resuelve al copiar dll no administrado al directorio bin de la aplicación web o servicio web.
Otra opción es incrustar la DLL nativa como un recurso en la DLL administrada. Esto es más complicado en ASP.NET, ya que requiere escribir en la carpeta temporal en tiempo de ejecución. La técnica se explica en otra respuesta SO .
Siempre vale la pena verificar la variable de ruta en la configuración de su entorno también.