Różnica między LoadFile i LoadFrom z zestawami .NET?

126

Przeglądałem dokumentację msdn i nadal jestem trochę zdezorientowany, jaka dokładnie jest różnica między używaniem LoadFilea LoadFromładowaniem zestawu. Czy ktoś może podać przykład lub analogię, aby lepiej to opisać. Dokumentacja MSDN bardziej mnie zmyliła. Ponadto ReflectionOnlyLoadFromdziała tak samo, jak LoadFromz tą różnicą, że ładuje zespół tylko w trybie odbicia.

Ponieważ moje doświadczenie z .NET nie jest najlepsze, oto kilka pytań dotyczących dokumentacji MSDN przy użyciu LoadFile:

1) Co to znaczy, że LoadFileanalizuje zespoły, które mają tę samą tożsamość, ale znajdują się na różnych ścieżkach? Jaka jest tożsamość (przykład)?

2) Stwierdza, że LoadFilenie ładuje plików do „LoadFrom Context” i nie rozwiązuje zależności za pomocą ścieżki ładowania. Co to znaczy, czy ktoś może podać przykład?

3) Na koniec stwierdza się, że LoadFilejest to przydatne w tym ograniczonym scenariuszu, ponieważ LoadFrom nie może załadować zestawów, które mają te same tożsamości, ale różne ścieżki; załaduje tylko pierwszy taki zestaw, co ponownie prowadzi mnie do tego samego pytania, jaka jest tożsamość zestawów?

Xaisoft
źródło
10
Poważnie myślę też czasami, że MS powinno zatrudniać lepszych pisarzy lub coś innego, ponieważ zdania nie zawsze są zrozumiałe ...
Tarik
7
Zobacz także undocumentation
Pułkownik Panic
1
@ColonelPanic MS może powiedzieć, że wszystko jest udokumentowane ... ale z zerowym współczynnikiem pomocy.
Legends,

Odpowiedzi:

96

Czy to wyjaśnia to?

// path1 and path2 point to different copies of the same assembly on disk:

Assembly assembly1 = Assembly.LoadFrom(path1);
Assembly assembly2 = Assembly.LoadFrom(path2);

// These both point to the assembly from path1, so this is true
Console.WriteLine(assembly1.CodeBase == assembly2.CodeBase);

assembly1 = Assembly.LoadFile(path1);
assembly2 = Assembly.LoadFile(path2);

// These point to different assemblies now, so this is false
Console.WriteLine(assembly1.CodeBase == assembly2.CodeBase);

Edycja : aby odpowiedzieć na pytania zadane w poprawionym pytaniu, na pewno chcesz przeczytać Suzanne Cook na temat Assembly Identity .

Istnieje wiele reguł, które regulują sposób ładowania zestawów, a niektóre z nich mają związek ze sposobem rozwiązywania zależności - jeśli AssemblyA jest zależna od AssemblyB, gdzie powinna szukać .NET, aby znaleźć AssemblyB? W Global Assembly Cache, w tym samym katalogu, w którym znalazł AssemblyA, czy zupełnie gdzie indziej? Ponadto, jeśli znajdzie wiele kopii tego zestawu, w jaki sposób powinien wybrać, którego użyć?

LoadFrom ma jeden zestaw reguł, podczas gdy LoadFile ma inny zestaw reguł. Trudno sobie wyobrazić wiele powodów, dla których warto skorzystać LoadFile, ale jeśli potrzebowałeś zastanowić się nad różnymi kopiami tego samego złożenia, to jest dla Ciebie.

Jeff Sternal
źródło
2
Czy CodeBase to to samo co Identity?
Xaisoft,
Nie, po prostu użyłem tutaj CodeBase jako arbitralnej właściwości zestawu, aby zilustrować, że druga instancja Assembly wskazywała na „zły” plik (w pierwszym przykładzie). Aktualizuję odpowiedź o więcej szczegółów.
Jeff Sternal
1
Trochę to czyści, ale w jaki sposób path1 i path2 wskazują różne kopie tego samego zestawu na dysku podczas korzystania z LoadFrom i podczas korzystania z LoadFile, path1 i path2 wskazują różne zestawy. Jaki jest przykład tego, jakie byłyby ścieżki path1 i path2? Dziękuję za cierpliwość.
Xaisoft
Dlaczego sprawdzasz dwa odwołania do ciągów pod kątem równości wartości z string.Compare(x, y) == 0? Myślę, że chcesz x == ytam? Jeśli z niejasnych powodów chcesz, aby sprawdzanie równości zależało od kultury string.Equals(x, y, StringComparison.CurrentCulture), na przykład bardziej jasne jest napisanie .
Jeppe Stig Nielsen
@JeffSternal Link na „Suzanne Cook on Assembly Identity” wydaje się być tutaj zepsuty ...
Martin Verjans
61

Z bloga Suzanne Cook :

LoadFile vs. LoadFrom

Uważaj - to nie to samo.

LoadFrom () przechodzi przez Fusion i może zostać przekierowany do innego zestawu w innej ścieżce, ale z tą samą tożsamością, jeśli jest już załadowany w kontekście LoadFrom.

LoadFile () w ogóle nie wiąże się z Fusion - moduł ładujący po prostu kontynuuje i ładuje dokładnie * to, czego zażądał wywołujący. Nie używa kontekstu Load ani LoadFrom.

Tak więc LoadFrom () zwykle daje ci to, o co prosiłeś, ale niekoniecznie. LoadFile () jest dla tych, którzy naprawdę chcą dokładnie tego, o co proszą. (* Jednak począwszy od wersji 2, zasady zostaną zastosowane zarówno do LoadFrom (), jak i LoadFile (), więc LoadFile () niekoniecznie będzie dokładnie tym, czego zażądano. Ponadto począwszy od wersji 2, jeśli zestaw z jego tożsamością jest w GAC, zamiast tego zostanie użyta kopia GAC. Użyj ReflectionOnlyLoadFrom (), aby załadować dokładnie to, co chcesz - ale pamiętaj, że zestawy załadowane w ten sposób nie mogą zostać wykonane).

LoadFile () ma haczyk. Ponieważ nie używa kontekstu powiązania, jego zależności nie są automatycznie odnajdywane w jego katalogu. Jeśli nie są dostępne w kontekście Load, musisz subskrybować zdarzenie AssemblyResolve, aby powiązać z nimi.

Zobacz tutaj .

Zobacz także artykuł o wybieraniu kontekstu powiązania na tym samym blogu.

CraigTP
źródło
Dzięki, sprawdzę bloga, zaktualizowałem post o kilka pytań dotyczących dokumentacji msdn.
Xaisoft,
@Xaisoft - blog Suzanne Cook znów przychodzi na ratunek z odpowiedzią w postaci tożsamości zgromadzeń. Zobacz blogs.msdn.com/suzcook/archive/2003/07/21/57232.aspx . Zasadniczo jest to „nazwa wyświetlana zestawu” i wygląda to mniej więcej tak: „System, Wersja = 1.0.3300.0, Kultura = neutralna, PublicKeyToken = b77a5c561934e089”, więc zawiera zarówno rzeczywistą nazwę zestawu, jego numer wersji, jak i inne informacje identyfikujące (takie jak PublicKeyToken itp.).
CraigTP
1
O czym ona ma na myśli, mówiąc o Fusion?
Xaisoft,
1
Rzeczywiście, Jeff jest na miejscu. Zobacz ten link: grimes.demon.co.uk/workshops/fusionWS.htm, aby zapoznać się z przyjemnym samouczkiem dotyczącym podsystemu Fusion i jego technologii do ładowania złożeń w .NET
CraigTP
1
Tylko szybka aktualizacja, pamiętaj, że powyższy adres URL (grimes.demon.co.uk/workshops/fusionWS.htm) nie jest już ważny i został przeniesiony do: richardgrimes.com/workshops/fusionWS.htm
CraigTP
45

Po wielu drapaniach po głowie sam odkryłem różnicę tego popołudnia.

Chciałem załadować bibliotekę DLL w czasie wykonywania, a biblioteka DLL mieszkała w innym katalogu. Ta biblioteka DLL miała własne zależności (biblioteki DLL), które również znajdowały się w tym samym katalogu.

LoadFile (): załadowano konkretną bibliotekę DLL, ale bez zależności. Więc kiedy pierwsze wywołanie zostało wykonane z wewnątrz biblioteki DLL do jednej z tych innych bibliotek DLL, zgłosiło wyjątek FileNotFoundException.

LoadFrom (): załadowano bibliotekę DLL, którą podałem, a także wszystkie zależności, które żyły w tym katalogu.

LordWilmore
źródło
4
To był dokładnie mój problem! Otrzymywałem to FileNotFoundExceptionpodczas tworzenia nowego wystąpienia obiektu zdefiniowanego w zestawie, do którego odwołuje się zestaw, który właśnie załadowałem .LoadFile. Zmiana tego na .LoadFromwydawała się rozwiązać problem, ale nie wiedziałem dlaczego! Dzięki
Connell,
1
Dziękuję, miałem ten sam problem.
Ivandro IG Jao
4

Uwaga: Jeśli jeden zestaw jest ładowany przy użyciu ścieżki 8.3, a następnie ze ścieżki innej niż 8.3, będą one postrzegane jako różne zestawy, nawet jeśli są to ta sama fizyczna biblioteka DLL.

Gregg DeMasters
źródło
0

jedna różnica, którą zauważyłem, to:

Assembly.LoadFile - ładuje zestaw w różnych AppDomain z ograniczonymi prawami użytkownika (różnica Principel). nie można wykonać operacji takich jak serilizacja / deserilizacja.

Assembly.LoadFrom - ładuje zestaw w tej samej AppDomain z tymi samymi prawami użytkownika (ten sam podmiot).

Lalit
źródło
3
To nie jest poprawne. Co sprawia, że ​​sądzisz, że Assembly.LoadFile ładuje zestaw do innej domeny AppDomain?
fr34kyn01535
0

W moim przypadku wystarczyło po prostu usunąć pamięć podręczną aplikacji ASP znajdującą się @ C:\Windows\Microsoft.NET\Framework\[asp version]\Temporary ASP.NET Files. Jest odbudowywany podczas pierwszego uruchomienia witryny. Pamiętaj, aby najpierw zatrzymać usługi IIS.

Mam nadzieję, że to pomoże komuś takiemu jak mnie.

David Roth
źródło