70

这个问题与一个 ASP.NET 网站有关,最初在 VS 2005 中开发,现在在 VS 2008 中开发。

该网站使用两个非托管外部 DLL,它们不是 .NET,我没有编译它们的源代码,必须按原样使用它们。

该网站在 Visual Studio 中运行良好,可以正确定位和访问这些外部 DLL。但是,当网站发布在网络服务器(运行 IIS6 和 ASP.NET 2.0)而不是开发 PC 上时,它无法定位和访问这些外部 DLL,并且我收到以下错误:

Unable to load DLL 'XYZ.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

外部 DLL 与包装它们的托管 DLL 以及网站的所有其他 DLL 一起位于网站的 bin 目录中。

搜索这个问题显示许多其他人似乎在从 ASP.NET 网站访问外部非 .NET DLL 时遇到同样的问题,但我还没有找到有效的解决方案。

我尝试了以下方法:

  • 运行 DEPENDS 检查依赖关系,确定前三个在路径中的 System32 目录中,最后一个在 .NET 2 框架中。
  • 我将这两个 DLL 及其依赖项放在 System32 中并重新启动服务器,但网站仍然无法加载这些外部 DLL。
  • 授予网站 bin 目录的 ASPNET、IIS_WPG 和 IUSR(对于该服务器)的完全权限并重新启动,但网站仍然无法加载这些外部 DLL。
  • 将外部 DLL 作为现有项目添加到项目中,并将其“复制到输出”属性设置为“始终复制”,网站仍然找不到 DLL。
  • 还将他们的“构建操作”属性设置为“嵌入式资源”,网站仍然找不到 DLL。

任何有关此问题的帮助将不胜感激!

4

11 回答 11

50

发生这种情况是因为托管 dll 将影子复制到 .NET Framework 目录下的临时位置。有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/ms366723.aspx

不幸的是,非托管 dll 不会被复制,并且 ASP.NET 进程在需要加载它们时将无法找到它们。

一种简单的解决方案是将非托管 dll 放在系统路径中的目录中(在命令行中键入“path”以查看计算机上的路径),以便 ASP.NET 进程可以找到它们。System32 目录始终位于路径中,因此将非托管 dll 放在那里总是可以的,但我建议在路径中添加一些其他文件夹,然后在此处添加 dll 以防止污染 System32 目录。此方法的一大缺点是您必须为应用程序的每个版本重命名非托管 dll,并且您可以快速拥有自己的 dll 地狱。

于 2009-05-14T05:23:51.133 回答
42

作为将 dll 放入路径中已经存在的文件夹(如 system32)的替代方法,您可以使用以下代码更改进程中的路径值

System.Environment.SetEnvironmentVariable("Path", searchPath + ";" + oldPath)

然后,当 LoadLibrary 尝试查找非托管 DLL 时,它还将扫描 searchPath。这可能比在 System32 或其他文件夹中弄得一团糟。

于 2011-01-04T21:44:39.760 回答
22

尝试将 dll 放在 \System32\Inetsrv 目录中。这是 Windows Server 上 IIS 的工作目录。

如果这不起作用,请尝试将 dll 放在 System32 目录中,并将依赖文件放在 Inetsrv 目录中。

于 2008-12-05T20:31:54.540 回答
12

添加到马特的回答中,这最终对我来说适用于 64 位服务器 2003 / IIS 6:

  1. 确保您的 dll / asp.net 版本相同(32 / 64 位)
  2. 将非托管 dll 放在 inetsrv 目录中(注意,在 64 位 Windows 中,这是在 syswow64 下,即使创建了 sys32/inetsrv 目录)
  3. 将托管 dll 留在 /bin
  4. 确保两组 dll 都具有读取/执行权限
于 2009-04-22T16:11:58.647 回答
6

看看FileMonProcMon并过滤麻烦的 DLL 的名称。这将向您显示在搜索 DLL 时扫描了哪些目录,以及您可能遇到的任何权限问题。

于 2008-12-05T20:37:21.753 回答
4

另一种选择是将本机 DLL 作为资源嵌入到托管 DLL 中。这在 ASP.NET 中更为复杂,因为它需要在运行时写入临时文件夹。 该技术在另一个 SO answer 中进行了解释

于 2012-06-20T16:34:30.550 回答
2

总是值得检查环境设置中的路径变量。

于 2008-12-05T20:39:04.433 回答
2

我遇到了同样的问题。我尝试了上述所有选项,复制到 system32、inetpub、设置路径环境等都没有奏效。这个问题最终通过将非托管 dll 复制到 web 应用程序或 web 服务的 bin 目录来解决。

于 2015-08-26T09:11:56.120 回答
2

在为这个问题苦苦挣扎了一整天之后,我终于找到了适合我的解决方案。这只是一个测试,但方法是有效的。

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();
                  }
                }
          }
        }
    }
}
于 2015-12-12T09:29:53.510 回答
1

直接在 XYZ.dll 上运行 DEPENDS,在您将其部署到的位置。如果这没有发现任何缺失,请使用平台 SDK 中的 fuslogvw 工具来跟踪加载程序错误。此外,事件日志有时包含有关加载 DLL 失败的信息。

于 2008-12-05T17:38:54.593 回答
0

在 Application_start 上使用:(根据需要自定义 /bin/x64 和 bin/dll/x64 文件夹)

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);
于 2018-06-30T21:11:21.587 回答