DLLs não gerenciados deixar de carga no servidor ASP.NET
Pergunta
Esta questão relaciona-se com um site ASP.NET, originalmente desenvolvido no VS 2005 e agora em VS 2008.
Este site usa dois DLLs externos não gerenciados que não .NET são e eu não tenho o código fonte para compilá-los e ter de usá-los como é.
Este site funciona muito bem de dentro do Visual Studio, localizar e acessar essas DLLs externas corretamente. No entanto, quando o site é publicado em um servidor web (runnning IIS6 e ASP.NET 2.0) em vez do PC desenvolvimento não pode localizar e acessar essas DLLs externas, e eu recebo o seguinte erro:
Unable to load DLL 'XYZ.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
As DLLs externos estão localizados no diretório bin do site, juntamente com as DLLs gerenciadas que envolvê-los e todas as outras DLLs para o site.
Como pesquisar este problema revela que muitas outras pessoas parecem ter o mesmo problema ao acessar non.NET DLLs a partir de sites externos ASP.NET, mas eu não encontrei uma solução que funciona.
Eu tentei o seguinte:
- Running DEPENDE para verificar as dependências para estabelecer que os três primeiros estão no diretório System32 no caminho, o último é no .NET 2 quadro.
- Eu coloquei as duas DLLs e suas dependências em System32 e reiniciado o servidor, mas o site ainda não poderia carregar essas DLLs externas.
- Deu plenos direitos para ASPNET, IIS_WPG e IUSR (para esse servidor) para o site diretório bin e reiniciado, mas o site ainda não podia carregar essas DLLs externas.
- Adicionado as DLLs externas como itens existentes para os projetos e conjunto sua "Copy to Output" propriedade para "Copy Always", e website ainda não conseguiu encontrar as DLLs.
- Também definir sua propriedade "Build Action" para "recurso incorporado" e website ainda não conseguiu encontrar as DLLs.
Qualquer ajuda com este problema seria muito apreciada!
Solução
Tente colocar as DLLs no diretório \ System32 \ Inetsrv. Este é o diretório de trabalho para o IIS no Windows Server.
Se isso não funcionar, tente colocar as DLLs no diretório System32 e os arquivos de dependência no diretório Inetsrv.
Outras dicas
Isso acontece porque as DLLs geridos se sombra copiados para um local temporário no diretório .NET Framework. Consulte http://msdn.microsoft.com/en-us/library/ms366723. aspx para mais detalhes.
Infelizmente, as DLLs não gerenciados não obter copiado e o processo ASP.NET não será capaz de encontrá-los quando ele precisa carregá-los.
Uma solução fácil é colocar as DLLs não gerenciados em um diretório que está no caminho do sistema (tipo "caminho" na linha de comando para ver o caminho em sua máquina) para que eles possam ser encontrados pelo processo ASP.NET . O diretório System32 é sempre no caminho, assim, colocar as DLLs não gerenciados há sempre funciona, mas eu recomendaria adicionar alguma outra pasta para o caminho e, em seguida, adicionar as DLLs lá para evitar poluir o diretório System32. Uma grande desvantagem deste método é que você tem que renomear as DLLs não gerenciadas para cada versão do seu aplicativo e você pode rapidamente ter seu próprio inferno dll.
Como uma alternativa para colocar a dll em uma pasta que já está no caminho (como system32) você pode alterar o valor do caminho em seu processo usando o seguinte código
System.Environment.SetEnvironmentVariable("Path", searchPath + ";" + oldPath)
Então, quando LoadLibrary tenta encontrar a DLL não gerenciado que também irá searchPath digitalização. Isso pode ser preferível fazer uma bagunça em System32 ou outras pastas.
Somando-se a resposta de Matt, isso é o que finalmente funcionou para mim para servidor de 64 bits 2003 / IIS 6:
- Verifique se seu dlls / asp.net são a mesma versão (32/64 bit)
- Coloque as DLLs não gerenciados no dir inetsrv (note que em 64 bits do Windows, este é sob syswow64, embora o diretório sys32 / inetsrv é criado)
- Deixe as DLLs geridos em / bin
- Certifique-se de ambos os conjuntos de dll leram / executar permissões
Outra opção é incorporar a DLL nativa como um recurso na DLL gerenciado. Isso é mais complicado em ASP.NET, uma vez que requer a escrita para a pasta temporária em tempo de execução. A técnica é explicada em outra resposta SO .
verificar o caminho variável em suas configurações de ambiente também.
Executar depende XYZ.dll diretamente, no local que você tenha sido implantado. Se isso não revelar nada faltando, use a ferramenta fuslogvw na plataforma SDK a erros carregador traço. Além disso, os logs de eventos, por vezes, contêm informações sobre as falhas para DLLs de carga.
Eu vim através de uma mesma questão. E eu tentei todas as opções acima, copiar para system32, inetpub, a criação de ambiente do caminho, etc nada funcionou. Esta questão está resolvida, copiando dll não gerenciada para o diretório bin de aplicação web ou serviço web.
?fter lutando durante todo o dia sobre este problema e, finalmente, eu encontrei uma solução que se adapte-me. É apenas um teste, mas o 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();
}
}
}
}
}
}
No Application_Start usar este: (Personalize / bin / x64 e bin / DLL / x64 pastas conforme necessário)
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);