Неуправляемые библиотеки DLL не загружаются на сервер ASP.NET

Этот вопрос относится к веб-сайту ASP.NET, первоначально разработанному в VS 2005, а теперь и в VS 2008.

Этот веб-сайт использует две неуправляемые внешние библиотеки DLL, которые не являются.NET, и у меня нет исходного кода для их компиляции, и я должен использовать их как есть.

Этот веб-сайт работает нормально из Visual Studio, правильно находя и обращаясь к этим внешним DLL. Однако, когда веб-сайт публикуется на веб-сервере (работающем под управлением IIS6 и ASP.NET 2.0), а не на компьютере разработчика, он не может найти эти внешние библиотеки DLL и получить к ним доступ, и я получаю следующую ошибку:

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

Внешние библиотеки DLL находятся в каталоге bin веб-сайта вместе с управляемыми библиотеками DLL, которые обертывают их, и всеми остальными библиотеками DLL для веб-сайта.

Поиск этой проблемы показывает, что многие другие люди, похоже, сталкиваются с той же проблемой при доступе к внешним не.NET DLL с веб-сайтов ASP.NET, но я не нашел решения, которое работает.

Я пробовал следующее:

  • Запуск DEPENDS для проверки зависимостей, чтобы установить, что первые три находятся в каталоге System32 в пути, последний находится в.NET 2 framework.
  • Я поместил две библиотеки DLL и их зависимости в System32 и перезагрузил сервер, но веб-сайт все еще не мог загрузить эти внешние библиотеки DLL.
  • Дали полные права ASPNET, IIS_WPG и IUSR (для этого сервера) на каталог bin веб-сайта и перезагрузились, но веб-сайт все еще не мог загрузить эти внешние библиотеки DLL.
  • Добавили внешние библиотеки в качестве существующих элементов в проекты и установили для их свойства "Копировать в вывод" значение "Копировать всегда", и веб-сайт по-прежнему не может найти библиотеки DLL.
  • Также установите для их свойства "Build Action" значение "Встроенный ресурс", и веб-сайт по-прежнему не сможет найти библиотеки DLL.

Любая помощь с этой проблемой будет принята с благодарностью!

12 ответов

Решение

Попробуйте поместить dll в каталог \System32\Inetsrv. Это рабочий каталог для IIS на Windows Server.

Если это не сработает, попробуйте поместить dll в каталог System32, а файлы зависимостей - в каталог Inetsrv.

Это происходит потому, что управляемые библиотеки dll копируются во временную папку в каталоге.NET Framework. См. http://msdn.microsoft.com/en-us/library/ms366723.aspx для получения подробной информации.

К сожалению, неуправляемые dll НЕ копируются, и процесс ASP.NET не сможет найти их, когда ему потребуется их загрузить.

Одним из простых решений является размещение неуправляемых библиотек в каталоге, который находится в системном пути (введите "путь" в командной строке, чтобы увидеть путь на вашем компьютере), чтобы они могли быть найдены процессом ASP.NET. Каталог System32 всегда находится в пути, поэтому размещение неуправляемых dll там всегда работает, но я бы порекомендовал добавить в путь какую-то другую папку и затем добавить dll, чтобы предотвратить загрязнение каталога System32. Один большой недостаток этого метода - вы должны переименовывать неуправляемые dll для каждой версии вашего приложения, и вы можете быстро иметь свой собственный ад dll.

В качестве альтернативы помещению DLL в папку, которая уже находится в пути (например, system32), вы можете изменить значение пути в вашем процессе, используя следующий код

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

Затем, когда LoadLibrary пытается найти неуправляемую DLL, она также сканирует searchPath. Это может быть предпочтительнее, чем создавать беспорядок в System32 или других папках.

В добавление к ответу Мэтта, это то, что в итоге сработало для меня на 64-битном сервере 2003 / IIS 6:

  1. убедитесь, что ваши dlls / asp.net имеют одинаковую версию (32 / 64 бит)
  2. Поместите неуправляемые библиотеки в inetsrv dir (обратите внимание, что в 64-битных окнах это находится под syswow64, даже если каталог sys32/inetsrv создан)
  3. Оставьте управляемые библиотеки в / bin
  4. Убедитесь, что оба набора DLL имеют права на чтение / выполнение

Взгляните на FileMon или ProcMon и отфильтруйте имена проблемных DLL. Это покажет вам, какие каталоги сканируются при поиске библиотек DLL, и любые проблемы с разрешениями, которые могут у вас возникнуть.

Другой вариант - встраивание собственной библиотеки DLL в качестве ресурса в управляемую библиотеку DLL. Это сложнее в ASP.NET, так как требует записи во временную папку во время выполнения. Техника объясняется в другом ответе SO.

После целого дня борьбы за эту проблему, и, наконец, я нашел решение, которое меня устраивает. Это всего лишь тест, но метод работает.

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

Я сталкивался с той же проблемой. И я перепробовал все вышеперечисленные варианты, скопировав в system32, inetpub, установив путь среды и т. Д. Ничего не получилось. Эта проблема, наконец, решается путем копирования неуправляемой библиотеки DLL в каталог bin веб-приложения или веб-службы.

Всегда стоит проверять переменную пути в настройках вашей среды.

Запустите DEPENDS непосредственно для XYZ.dll в том месте, в котором вы его развернули. Если это не выявит ничего недостающего, используйте инструмент fuslogvw в SDK платформы для отслеживания ошибок загрузчика. Кроме того, журналы событий иногда содержат информацию о сбоях при загрузке DLL.

Попробуйте поместить DLL в папку Windows/SysWOW64. Это было единственное, что сработало для меня.

На 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);
Другие вопросы по тегам