Sdílet prostřednictvím


Osvědčené postupy pro načítání sestavení

Poznámka:

Tento článek je specifický pro rozhraní .NET Framework. Nevztahuje se na novější implementace .NET, včetně .NET 6 a novějších verzí.

Tento článek popisuje způsoby, jak se vyhnout problémům s identitou typu, které můžou vést k InvalidCastException, MissingMethodExceptiona dalším chybám. Článek popisuje následující doporučení:

První doporučení, porozumět výhodám a nevýhodám kontextů zatížení, poskytuje základní informace pro ostatní doporučení, protože všechny závisejí na znalostech kontextů zatížení.

Vysvětlení výhod a nevýhod kontextů zatížení

V rámci domény aplikace je možné sestavení načíst do jednoho ze tří kontextů nebo je lze načíst bez kontextu:

  • Výchozí kontext načítání obsahuje sestavení nalezená pomocí prohledávání globální mezipaměti sestavení, úložiště sestavení hostujícího, pokud je modul runtime hostovaný (například v SQL Server), a ApplicationBase a PrivateBinPath domény aplikace. Většina přetížení metody Load slouží k načítání sestavení do tohoto kontextu.

  • Kontext načítání obsahuje sestavení, která jsou načtena z míst, jež zavaděč neprohledává. Doplňky můžou být například nainstalovány v adresáři, který není pod cestou aplikace. Assembly.LoadFrom, AppDomain.CreateInstanceFrom a AppDomain.ExecuteAssembly jsou příklady metod, které se načítají podle cesty.

  • Kontext pouze pro reflektivní činnosti obsahuje sestavení načtená pomocí metod ReflectionOnlyLoad a ReflectionOnlyLoadFrom. Kód v tomto kontextu nelze spustit, takže zde není popsán. Další informace naleznete v tématu Jak: Načíst sestavení do kontextu Reflection-Only.

  • Pokud jste vygenerovali přechodné dynamické sestavení pomocí generování reflexe, sestavení není v žádném kontextu. Kromě toho se většina sestavení načtených pomocí metody LoadFile načte bez kontextu a sestavení načtená z byte arrays jsou načtena bez kontextu, pokud jejich identita sestavení (po použití politiky) nenaváže, že jsou v globální mezipaměti sestavení.

Kontexty provádění mají výhody a nevýhody, jak je popsáno v následujících částech.

Výchozí kontext načtení

Při načtení sestavení do výchozího kontextu načítání se jejich závislosti načtou automaticky. Závislosti načtené do výchozího kontextu načítání jsou automaticky rozpoznány pro sestavení ve výchozím kontextu načítání nebo kontextu Načíst z. Načítání podle identity sestavení zvyšuje stabilitu aplikací tím, že zajišťuje, aby se nepoužívaly neznámé verze sestavení (viz část Vyhněte se vazbě u částečných názvů sestavení).

Použití výchozího kontextu načítání má následující nevýhody:

  • Závislosti načtené do jiných kontextů nejsou k dispozici.

  • Nelze načítat sestavení z umístění mimo cestu sondování do výchozího kontextu načítání.

kontext Load-From

Kontext načtení z cesty umožňuje načíst sestavení z cesty, která není pod cestou aplikace, a proto není zahrnuta do vyhledávání. Umožňuje umístění a načtení závislostí z této cesty, protože informace o cestě jsou udržovány kontextem. Sestavení v tomto kontextu mohou navíc používat závislosti, které jsou načteny do výchozího kontextu načítání.

Načítání sestavení pomocí metody Assembly.LoadFrom nebo jedné z dalších metod, které načítají podle cesty, má následující nevýhody:

  • Pokud je sestavení se stejnou identitou již načteno v kontextu načtení z kontextu, LoadFrom vrátí načtené sestavení i v případě, že byla zadána jiná cesta.

  • Pokud je sestavení načteno pomocí LoadFrom a později se sestavení ve výchozím kontextu načtení pokusí nahrát stejné sestavení podle jeho zobrazovaného názvu, pokus o načtení selže. K tomu může dojít při deserializaci sestavení.

  • Pokud je sestavení načteno s LoadFrom a cesta testování obsahuje sestavení se stejnou identitou, ale v jiném umístění, může dojít k InvalidCastException, MissingMethodException nebo jinému neočekávanému chování.

  • LoadFrom požadavky FileIOPermissionAccess.Read a FileIOPermissionAccess.PathDiscovery, nebo WebPermission na zadané cestě.

  • Pokud pro sestavení existuje nativní obraz, nebude použit.

  • Sestavení nelze načíst jako doménově neutrální.

  • V rozhraní .NET Framework verze 1.0 a 1.1 se zásady nepoužijí.

Bez kontextu

Načítání bez kontextu je jedinou možností pro přechodná sestavení generovaná pomocí generování reflexe. Načítání bez kontextu je jediným způsobem, jak načíst více sestavení, která mají stejnou identitu do jedné domény aplikace. Nákladům na sondování je se vyhnuto.

Sestavení načtená z bajtových polí jsou načtena bez kontextu, pokud identita sestavení, která je vytvořena při použití zásad, odpovídá identitě sestavení v globální mezipaměti sestavení; v takovém případě se sestavení načte z globální mezipaměti sestavení.

Načítání sestavení bez kontextu má následující nevýhody:

  • Jiná sestavení nemohou navazovat vazbu na sestavení, která jsou načtena bez kontextu, pokud nezpracujete událost AppDomain.AssemblyResolve.

  • Závislosti se nenačtou automaticky. Můžete je předem načíst bez kontextu, načíst do výchozího kontextu, nebo je načíst zpracováním události AppDomain.AssemblyResolve.

  • Načítání více sestavení se stejnou identitou bez kontextu může vést k potížím s identitou typu, podobně jako načítání sestavení se stejnou identitou do více kontextů. Viz Vyhněte se načítání sestavení do více kontextů.

  • Pokud pro sestavení existuje nativní obraz, nebude použit.

  • Sestavení nelze načíst jako doménově neutrální.

  • V rozhraní .NET Framework verze 1.0 a 1.1 se zásady nepoužijí.

Vyhněte se vazbám u částečných názvů sestavení.

Částečné navázání názvu nastane, když při načítání sestavení zadáte pouze část zobrazovaného názvu sestavení (FullName). Můžete například volat metodu Assembly.Load pouze s jednoduchým názvem sestavení, vynecháním verze, jazykové verze a tokenu veřejného klíče. Nebo můžete volat metodu Assembly.LoadWithPartialName , která nejprve volá metodu Assembly.Load a pokud se sestavení nepodaří najít, vyhledá globální mezipaměť sestavení a načte nejnovější dostupnou verzi sestavení.

Částečná vazba názvu může způsobit mnoho problémů, včetně následujících:

  • Metoda Assembly.LoadWithPartialName může načíst jiné sestavení se stejným jednoduchým názvem. Například dvě aplikace mohou nainstalovat dvě zcela odlišná sestavení, která mají oba jednoduchý název GraphicsLibrary do globální mezipaměti sestavení.

  • Sestavení, které je skutečně načteno, nemusí být zpětně kompatibilní. Pokud například nezadáte verzi, může se stát, že se načítá mnohem novější verze než verze, kterou váš program původně napsal k použití. Změny v novější verzi můžou způsobit chyby ve vaší aplikaci.

  • Sestavení, které je skutečně načteno, nemusí být kompatibilní s budoucími verzemi. Můžete například sestavit a otestovat aplikaci s nejnovější verzí sestavení, ale částečná vazba může načíst mnohem starší verzi, která nemá funkce, které vaše aplikace používá.

  • Instalace nových aplikací může narušit stávající aplikace. Aplikaci, která používá metodu LoadWithPartialName , může být přerušena instalací novější nekompatibilní verze sdíleného sestavení.

  • Neočekávané načítání závislostí může nastat. Pokud načtete dvě sestavení, která sdílejí závislost, jejich načtení s částečnou vazbou může mít za následek, že jedno sestavení použije komponentu, pro kterou nebylo sestaveno ani testováno.

Kvůli problémům, které může způsobit, LoadWithPartialName byla metoda označena zastaralá. Doporučujeme, abyste místo toho použili metodu Assembly.Load a zadali úplné zobrazované názvy sestavení. Přečtěte si o výhodách a nevýhodách kontextů načítání a zvažte přepnutí na výchozí kontext načítání.

Pokud chcete použít metodu LoadWithPartialName, protože usnadňuje načítání sestavení, zvažte, že aplikace, která selže a zobrazí chybovou zprávu identifikující chybějící sestavení, pravděpodobně poskytne lepší uživatelský zážitek než automatické použití neznámé verze sestavení, což by mohlo způsobit nepředvídatelné chování a bezpečnostní rizika.

Vyhněte se načítání sestavení do více kontextů

Načtení sestavení do různých kontextů může vést k problémům s identitou typů. Pokud je stejný typ načten ze stejného sestavení do dvou různých kontextů, je to jako kdyby byly načteny dva různé typy se stejným názvem. InvalidCastException je vyvolána, pokud se pokusíte přetypovat jeden typ na druhý, s matoucí zprávou, že typ MyType nelze přetypovat na typ MyType.

Předpokládejme například, že ICommunicate rozhraní je deklarováno v sestavení s názvem Utility, které je odkazováno vaším programem a také jinými sestaveními, která program načte. Tato další sestavení obsahují typy, které implementují ICommunicate rozhraní, což umožňuje, aby je program používal.

Teď zvažte, co se stane, když je program spuštěný. Sestavení, na která odkazuje váš program, se načtou do výchozího kontextu načítání. Pokud načtete cílové sestavení podle jeho identity pomocí Load metody, bude ve výchozím kontextu načítání, stejně tak i jeho závislosti. Program i cílové sestavení budou používat stejné Utility sestavení.

Předpokládejme však, že cílové sestavení načtete cestou k souboru pomocí LoadFile metody. Sestavení se načte bez jakéhokoli kontextu, takže jeho závislosti se nenačtou automaticky. Pro událost můžete mít obslužnou rutinu AppDomain.AssemblyResolve pro poskytnutí závislosti a může načíst Utility sestavení bez kontextu pomocí LoadFile metody. Nyní když vytvoříte instanci typu, která je obsažena v cílovém sestavení, a pokusíte se ji přiřadit proměnné typu ICommunicate, je vyvolána výjimka InvalidCastException, protože modul runtime považuje rozhraní ICommunicate ve dvou kopiích sestavení Utility za různé typy.

Existuje mnoho dalších scénářů, ve kterých lze sestavení načíst do více kontextů. Nejlepším přístupem je vyhnout se konfliktům tak, že cílové sestavení přesunete do cesty aplikace a použijete Load metodu s úplným zobrazovaným názvem. Sestavení se pak načte do výchozího kontextu načítání a obě sestavení používají stejné Utility sestavení.

Pokud cílové sestavení musí zůstat mimo cestu aplikace, můžete použít LoadFrom metodu k jeho načtení do kontextu načítání. Pokud bylo cílové sestavení zkompilováno s odkazem na sestavení vaší aplikace Utility , použije Utility sestavení, které aplikace načetla do výchozího kontextu načítání. Mějte na paměti, že k problémům může dojít, pokud cílové sestavení má závislost na kopii Utility sestavení umístěné mimo cestu aplikace. Pokud je toto sestavení načteno do kontextu načtení před načtením sestavení Utility vaší aplikace, načtení aplikace selže.

Část Zvažte přepnutí na výchozí kontext načtení popisuje alternativy k použití cest k souborům, jako jsou LoadFile a LoadFrom.

Vyhněte se načítání více verzí sestavení do stejného kontextu.

Načtení více verzí sestavení do jednoho kontextu načítání může způsobit problémy s identitou typu. Pokud je stejný typ načten ze dvou verzí stejného sestavení, je to jako kdyby byly načteny dva různé typy se stejným názvem. InvalidCastException je vyvolána, pokud se pokusíte přetypovat jeden typ na druhý, s matoucí zprávou, že typ MyType nelze přetypovat na typ MyType.

Program může například načíst jednu verzi Utility sestavení přímo a později může načíst jiné sestavení, které načte jinou verzi Utility sestavení. Nebo kódovací chyba může způsobit, že dvě různé cesty kódu ve vaší aplikaci načtou různé verze sestavení.

Ve výchozím kontextu načtení může k tomuto problému dojít, když použijete metodu Assembly.Load a zadáte úplné názvy sestavení obsahující různá čísla verzí. U sestavení, která jsou načtena bez kontextu, může být příčinou problému použití Assembly.LoadFile metody načtení stejného sestavení z různých cest. Runtime prostředí považuje dvě sestavení načtená z různých cest za různá sestavení, i když jsou jejich identity stejné.

Kromě problémů s identitou typu může více verzí sestavení způsobit MissingMethodException , že typ načtený z jedné verze sestavení se předá kódu, který očekává tento typ z jiné verze. Například kód může očekávat metodu, která byla přidána do novější verze.

K podrobnějším chybám může dojít v případě, že se chování typu mezi verzemi změnilo. Například metoda může vyvolat neočekávanou výjimku nebo vrátit neočekávanou hodnotu.

Pečlivě zkontrolujte kód a ujistěte se, že je načtena pouze jedna verze sestavení. Pomocí metody AppDomain.GetAssemblies můžete určit, která sestavení se v daném okamžiku načtou.

Zvažte přepnutí na výchozí kontext načítání.

Prozkoumejte způsoby načítání modulů a nasazení vaší aplikace. Můžete eliminovat sestavení, která jsou načtena z bajtových polí? Můžete přesunout sestavení do sondovací cesty? Pokud jsou sestavení umístěna v globální mezipaměti sestavení nebo v cestě k sondování domény aplikace (tj. její ApplicationBase a PrivateBinPath), můžete sestavení načíst podle identity sestavení.

Pokud není možné umístit všechna sestavení do cesty sondování, zvažte alternativy, jako je použití modelu doplňků .NET Framework, umístění sestavení do globální mezipaměti sestavení nebo vytváření domén aplikací.

Zvažte použití modelu Add-In rozhraní .NET Framework

Pokud používáte kontext načítání k implementaci doplňků, které obvykle nejsou nainstalovány v základně aplikace, použijte model doplňků .NET Framework. Tento model poskytuje izolaci na úrovni domény aplikace nebo procesu, aniž byste museli spravovat domény aplikace sami. Informace o modelu doplňku naleznete v tématu Doplňky a rozšiřitelnost.

Zvažte použití globálního úložiště sestavení

Umístěte sestavení do globální mezipaměti sestavení, abyste získali výhodu sdílené cesty sestavení, která je mimo základ aplikace, aniž by došlo ke ztrátě výhod výchozího kontextu zatížení nebo ke nevýhodám ostatních kontextů.

Zvažte použití domén aplikací.

Pokud zjistíte, že některá sestavení nelze nasadit v cestě pro zkoumání aplikace, zvažte vytvoření nové domény aplikace pro tato sestavení. Použijte AppDomainSetup k vytvoření nového aplikačního doménového prostoru a vlastnost AppDomainSetup.ApplicationBase použijte k zadání cesty, která obsahuje sestavení, jež chcete načíst. Pokud máte k prozkoumání více adresářů, můžete nastavit ApplicationBase jako kořenový adresář a pomocí AppDomainSetup.PrivateBinPath vlastnosti identifikovat podadresáře, které chcete prozkoumat. Alternativně můžete vytvořit více domén aplikace a nastavit ApplicationBase každé domény aplikace na odpovídající cestu pro sestavení těchto domén.

Pamatujte, že k načtení těchto sestavení můžete použít metodu Assembly.LoadFrom. Vzhledem k tomu, že nyní jsou v cestě zkoumání, budou načteny do výchozího kontextu načítání namísto kontextu načítání z určitého místa. Doporučujeme však přepnout na metodu Assembly.Load a zadat úplné zobrazované názvy sestavení, abyste zajistili, že se vždy použijí správné verze.

Viz také