【问题标题】:Unmanaged DLLs fail to load on ASP.NET server非托管 DLL 无法在 ASP.NET 服务器上加载
【发布时间】:2010-09-25 13:38:29
【问题描述】:

这个问题与一个 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。
  • 授予 ASPNET、IIS_WPG 和 IUSR(针对该服务器)的全部权限 网站bin目录并重新启动,但网站仍然无法 加载这些外部 DLL。
  • 将外部 DLL 作为现有项目添加到项目并设置 他们的“复制到输出”属性为“始终复制”,以及网站 仍然找不到 DLL。
  • 还将他们的“构建操作”属性设置为“嵌入式资源”和 网站仍然找不到 DLL。

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

【问题讨论】:

    标签: asp.net dll iis-6 unmanaged


    【解决方案1】:

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

    【讨论】:

    • 你能链接到我可以得到 DEPENDS 的地方吗?
    【解决方案2】:

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

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

    【讨论】:

    • 这是一个无需污染system32文件夹的答案:stackoverflow.com/a/4598747/92756
    • 相反,您可以通过在 web.config 上添加 来禁用 ShadowCopying,前提是您没有在实时应用程序中修改二进制文件。
    • 复制我的 DLL 并将其放入 System32 中,因为我忘记了它而被烧毁了,然后我为我的加载了错误版本的 Microsoft.Azure.Documents.ServiceInterop.dll尝试连接到数据库时导致奇怪的本地 queryRanges[0].isMinInclusive 错误的项目。我的修复最终是确保我的本地 IIS DefaultAppPool 身份是我的本地用户。另见:github.com/Azure/azure-documentdb-dotnet/issues/267
    • 你拯救了我的一天,+1
    【解决方案3】:

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

    【讨论】:

    • ProcMon 在确定依赖关系以及某个 DLL 不会加载的内容方面非常有用。
    【解决方案4】:

    在您的环境设置中也总是值得 checking the path 变量。

    【讨论】:

    • @Ristogod:答案是四岁,你对我投了反对票,因为我没有跟踪以确保链接处于活动状态?艰难的人群。
    • @annakata 你应该从链接中提取重要信息,所以当链接失败时,这个答案仍然有效;)
    • @Drax - 我认为重要的信息是检查你的路径变量
    • @annakata 答案对我来说已经足够清楚了,但对于所有感兴趣的用户来说可能不是那么容易解释:)
    【解决方案5】:

    除了马特的回答之外,这对我来说最终适用于 64 位服务器 2003 / IIS 6:

    1. 确保您的 dll / asp.net 版本相同(32 / 64 位)
    2. 将非托管 dll 放入 inetsrv 目录(请注意,在 64 位 Windows 中,这是在 syswow64 下,即使已创建 sys32/inetsrv 目录)
    3. 将托管 dll 留在 /bin 中
    4. 确保两组 dll 都具有读取/执行权限

    【讨论】:

    • +1 表示 inetsrv 在 64 位系统上的位置。谢谢你。
    【解决方案6】:

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

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

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

    【讨论】:

    • 这是一个比接受的答案更好的答案,因为它解释了您为什么要这样做。
    • 根据我的经验,当我创建一个新目录时,将其添加到PATH并将DLL放在那里,在本地运行时发现它很好。但是,托管在 IIS 上时情况并非如此——只有当我在 /Windows/System32 中找到 DLL 时才能找到该 DLL。在某些情况下,IIS 是否可能对路径使用不同的变量?
    【解决方案7】:

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

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

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

    【讨论】:

    • 仅适用于 PInvoke。如果使用混合模式程序集,则 DLL 会在任何代码运行之前链接(并失败)。
    【解决方案8】:

    另一种选择是将本机 DLL 作为资源嵌入到托管 DLL 中。这在 ASP.NET 中更为复杂,因为它需要在运行时写入临时文件夹。 The technique is explained in another SO answer.

    【讨论】:

    • 对于可能在 PAAS 主机(如 Azure 网站)中运行或使用的应用程序或库,我不推荐这种方法。
    • 你为什么不推荐这个?我正在考虑将此方法用于需要从托管程序集运行本机可执行文件的 Azure Functions 应用程序。
    • Azure 函数在我编写时并不存在。 Azure Functions 是如此的小而有针对性,如果你让它工作,那就去吧!
    【解决方案9】:

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

    【讨论】:

      【解决方案10】:

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

      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();
                        }
                      }
                }
              }
          }
      }
      

      【讨论】:

        【解决方案11】:

        在 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);
        

        【讨论】:

          猜你喜欢
          • 2019-08-15
          • 2014-03-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-23
          • 2013-06-24
          相关资源
          最近更新 更多