2008-12-05 13 views
60

To pytanie odnosi się do strony internetowej ASP.NET, pierwotnie opracowany w VS 2005 i teraz w VS 2008.Niezarządzane DLL nie można załadować na serwer ASP.NET

Ta strona używa dwóch niezarządzanych DLL zewnętrznych, które nie są .NET i nie mam kodu źródłowego, aby je skompilować i używać ich tak, jak jest.

Ta strona działa poprawnie z poziomu Visual Studio, znajdując i uzyskując dostęp do zewnętrznych bibliotek DLL. Jednak, gdy strona jest na serwerze internetowym opublikował (runnning IIS6 i ASP.NET 2.0) zamiast komputera rozwoju nie może zlokalizować i dostęp do tych zewnętrznych bibliotek DLL, i pojawia się następujący błąd:

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

zewnętrzne biblioteki DLL znajdują się w katalogu bin witryny, wraz z zarządzanymi bibliotekami DLL, które je zawijają, oraz wszystkimi innymi bibliotekami DLL witryny.

Poszukiwanie tego problemu ujawnia, że ​​wiele osób ma ten sam problem z dostępem do zewnętrznych bibliotek DLL innych niż .NET ze stron ASP.NET, ale nie znalazłem rozwiązania, które działa.

Próbowałem następujące:

  • Bieg zależy sprawdzi zależności ustalić, że pierwsze trzy są w katalogu System32 w ścieżce, ostatnia jest w .NET 2 ram.
  • Umieściłem dwie biblioteki DLL i ich zależności w System32 i zrestartowałem serwer, ale strona internetowa nadal nie mogła załadować tych zewnętrznych bibliotek DLL.
  • Użytkownik uzyskał pełne prawa do ASPNET, IIS_WPG i IUSR (dla tego serwera) do katalogu bin witryny i zrestartował, ale strona internetowa nadal nie mogła załadować tych zewnętrznych bibliotek DLL na adres .
  • Dodano zewnętrzne biblioteki DLL jako istniejące elementy do projektów i ustawiono ich właściwość "Kopiuj na wyjście" na "Kopiuj zawsze", a strona internetowa nadal nie może znaleźć plików DLL.
  • Ustaw również ich właściwość "Kompilacja działania" na "Zasób osadzony", a strona internetowa nadal nie może znaleźć plików DLL.

Każda pomoc z tym problemem byłaby bardzo ceniona!

Odpowiedz

21

Spróbuj umieścić pliki dll w katalogu \ System32 \ Inetsrv. To jest katalog roboczy dla IIS na Windows Server.

Jeśli to nie działa, spróbuj umieścić pliki dll w katalogu System32 i pliki zależności w katalogu Inetsrv.

+3

Oto odpowiedź bez potrzeby zanieczyszczania folderu system32: http://stackoverflow.com/a/4598747/92756 –

+4

zamiast tego, możesz wyłączyć ShadowCopying przez dodanie < hostingEnvironment shadowCopyBinAssemblies = "false" /> na web.config, pod warunkiem, że nie modyfikujesz plików binarnych w aplikacji na żywo. – Amit

+0

Zostałem spalony przez zrobienie kopii mojej biblioteki DLL i umieszczenie jej w System32, ponieważ zapomniałem o niej, a następnie załadowałem nieprawidłową wersję Microsoft.Azure.Documents.ServiceInterop.dll dla mojego projektu, co zaowocowało dziwnymi lokalnymi zapytaniami [0] .isMinInclusive błędy podczas próby połączenia z bazą danych.Moja poprawka polegała na tym, aby upewnić się, że moja lokalna tożsamość IIS DefaultAppPool była moim lokalnym użytkownikiem. Zobacz także: https://github.com/Azure/azure-documentdb-dotnet/issues/267 – Zachstronaut

1

Uruchamiaj ZADANIA na XYZ.dll bezpośrednio w lokalizacji, w której został wdrożony. Jeśli nic nie odkryjesz, użyj narzędzia fuslogvw w zestawie SDK platformy, aby prześledzić błędy programu ładującego. Ponadto dzienniki zdarzeń czasami zawierają informacje o błędach ładowania bibliotek DLL.

+0

Czy możesz umieścić link do miejsca, w którym mogę uzyskać ZALEŻNOŚCI? –

+0

Tutaj jest: http://www.dependencywalker.com/ – Werg38

6

Spójrz na numer FileMon lub ProcMon i odfiltruj nazwy kłopotliwych bibliotek DLL. Spowoduje to wyświetlenie, które katalogi są skanowane w poszukiwaniu bibliotek DLL i wszelkich problemów związanych z uprawnieniami.

+1

ProcMon jest niezwykle przydatny w ustalaniu zależności i tego, czego nie można załadować określonej biblioteki DLL. – Oliver

1

Zawsze warto zmienna również w ustawieniach środowiska.

+0

link nie ma miejsca, gdzie – Ristogod

+7

@Ristogod: Odpowiedź jest cztery lata i jesteś downvoting mnie, ponieważ nie śledzić, aby upewnić się, że link był aktywny? Twardy tłum. – annakata

+2

@annakata Powinieneś wyodrębnić ważne informacje z linku, więc kiedy się ułoży, ta odpowiedź jest nadal aktualna;) – Drax

10

Dodawanie do odpowiedzi Matta, to co ostatecznie pracował dla mnie na 64-bitowym Server 2003/IIS 6:

  1. upewnić się, że pliki DLL/asp.net jest taka sama wersja (32/64-bitowy)
  2. Put niezarządzanych dLL w katalogu inetsrv (zauważ, że w 64-bitowych systemach Windows, to jest pod SysWOW64 choć tworzony jest katalog sys32/inetsrv)
  3. opuścić zarządzanych dLL w/bin
  4. Upewnij oba zestawy dll mają uprawnienia do odczytu/wykonywania
+0

+1 dla lokalizacji inetsrv na 64-bitowych systemach. Dziękuję za to. –

39

Dzieje się tak, ponieważ zarządzane biblioteki dll są kopiowane w cień do lokalizacji tymczasowej w katalogu .NET Framework. Szczegóły: http://msdn.microsoft.com/en-us/library/ms366723.aspx.

Niestety, biblioteki niezarządzane NIE są kopiowane, a proces ASP.NET nie będzie w stanie ich znaleźć, gdy będzie trzeba je załadować.

Jednym z łatwych rozwiązań jest umieszczenie niezarządzanych bibliotek dll w katalogu znajdującym się w ścieżce systemowej (wpisz "ścieżka" w wierszu poleceń, aby zobaczyć ścieżkę na twoim komputerze), aby można je było znaleźć w ASP.NET proces. Katalog System32 jest zawsze zawsze w ścieżce, więc umieszczanie niezarządzanych bibliotek DLL zawsze działa, ale polecam dodanie do ścieżki innego folderu, a następnie dodanie tam bibliotek dll, aby zapobiec zanieczyszczaniu katalogu System32. Jedną dużą wadą tej metody jest zmiana nazwy niezarządzanych bibliotek dll dla każdej wersji aplikacji i możesz szybko mieć własne piekło.

+2

To jest lepsza odpowiedź niż zaakceptowana odpowiedź, ponieważ wyjaśnia, dlaczego chcesz to zrobić. –

+0

Z mojego doświadczenia wynika, że ​​kiedy tworzę nowy katalog, dodam go do PATH i wstawiam tam bibliotekę DLL, to jest dobrze, gdy działa lokalnie. Nie dotyczy to jednak hostowania w IIS - biblioteka DLL jest dostępna tylko wtedy, gdy mam ją w/Windows/System32. Czy w niektórych przypadkach usługi IIS mogą używać innej zmiennej dla ścieżki? –

35

Jako alternatywny do oddania dll w folderze, który jest już w drodze (jak system32) można zmienić wartość ścieżki w procesie za pomocą następującego kodu

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

Wtedy kiedy LoadLibrary próbuje znajdź niezarządzaną bibliotekę DLL, która również zeskanuje searchPath. To może być lepsze niż bałagan w System32 lub innych folderach.

+8

Absolutnie genialny! Prosty, bezpośredni, rozwiązał mój problem. –

+3

Jest to znacznie lepsza odpowiedź akceptująca, jak sądzę. –

+4

Działa tylko z PInvoke. jeśli używasz zespołu trybu mieszanego, biblioteki DLL są połączone (i kończą się niepowodzeniem) przed uruchomieniem dowolnego kodu. –

3

Inną opcją jest osadzenie natywnej biblioteki DLL jako zasobu w zarządzanej bibliotece DLL. Jest to bardziej skomplikowane w ASP.NET, ponieważ wymaga zapisu w folderze tymczasowym w środowisku wykonawczym. The technique is explained in another SO answer.

+0

Nie polecam tego podejścia dla aplikacji lub bibliotek, które mogą być uruchamiane lub używane na hostach PAAS (jak witryny internetowe Azure). – yzorg

+0

dlaczego nie poleciłbyś tego? Rozważam zastosowanie tego podejścia do aplikacji Azure Functions, w której muszę uruchomić natywny plik wykonywalny z zespołu zarządzanego. –

+0

Funkcje Azure nie istniały, gdy je napisałem. Funkcje Azure są tak małe i ukierunkowane, jeśli działasz, to idź do niego! – yzorg

1

Natrafiłem na ten sam problem. I wypróbowałem wszystkie powyższe opcje, kopiowanie do system32, inetpub, ustawienie środowiska ścieżki, itp. Nic nie działało. Ten problem można rozwiązać, kopiując niezarządzaną bibliotekę dll do katalogu bin aplikacji WWW lub usługi WWW.

1

Po całym dniu przezwyciężania tego problemu i wreszcie znalazłem rozwiązanie, które mi odpowiada. To tylko test, ale metoda działa.

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(); 
        } 
       } 
      } 
     } 
    } 
} 
Powiązane problemy