Doporučené postupy pro načtení 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í zbídání globální mezipaměti sestavení, úložiště sestavení hostitele, pokud je modul runtime hostovaný (například v SQL Serveru) a ApplicationBasePrivateBinPath doména aplikace. Většina přetížení Load sestavení metody načítá do tohoto kontextu.

  • Načtení z kontextu obsahuje sestavení načtená z umístění, která zavaděč nehledají. Doplňky můžou být například nainstalovány v adresáři, který není pod cestou aplikace. Assembly.LoadFrom, AppDomain.CreateInstanceFroma AppDomain.ExecuteAssembly jsou příklady metod, které se načítají cestou.

  • Kontext jen pro odraz obsahuje sestavení načtená pomocí ReflectionOnlyLoad metod a ReflectionOnlyLoadFrom metod. Kód v tomto kontextu nelze spustit, takže zde není popsán. Další informace naleznete v tématu Postupy: Načtení sestavení do kontextu pouze reflexe.

  • 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í LoadFile metody načte bez kontextu a sestavení načtená z bajtových polí jsou načtena bez kontextu, pokud jejich identita (po použití zásady) 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í se automaticky nacházejí pro sestavení ve výchozím kontextu načtení nebo pro načtení z kontextu. Načítání identit 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.

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

Načtení z kontextu

Kontext načítání umožňuje načíst sestavení z cesty, která není pod cestou aplikace, a proto není zahrnuta do sondy. 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í Assembly.LoadFrom metody nebo jedné z dalších metod, které načítají cestou, 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 s LoadFroma později sestavení ve výchozím kontextu načtení se pokusí načíst stejné sestavení podle 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 LoadFroma cesta sondy obsahuje sestavení se stejnou identitou, ale v jiném umístění, může InvalidCastExceptionMissingMethodExceptiondojít k neočekávanému chování nebo jinému neočekávanému chování.

  • LoadFrom požadavky FileIOPermissionAccess.Read a FileIOPermissionAccess.PathDiscoverynebo , WebPermissionna zadané cestě.

  • Pokud pro sestavení existuje nativní bitová kopie, nepoužívá se.

  • 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áklady na zkušební testování se vyhnete.

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 svázat se sestaveními, která jsou načtena bez kontextu, pokud nezpracujete AppDomain.AssemblyResolve událost.

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

  • Načtení více sestavení se stejnou identitou bez kontextu může způsobit problémy s identitou typu podobné těm, které způsobují načítání sestavení se stejnou identitou do více kontextů. Podívejte se, jak se vyhnout načtení sestavení do více kontextů.

  • Pokud pro sestavení existuje nativní bitová kopie, nepoužívá se.

  • 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á vazba názvu nastane, když při načtení 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í dopředu. 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í.

  • Může dojít k neočekávanému načítání závislostí. Načte dvě sestavení, která sdílejí závislost, jejich načtení s částečnou vazbou může vést k tomu, že jedno sestavení použije komponentu, se kterou nebyla sestavena nebo testována.

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

Pokud chcete použít metodu LoadWithPartialName , protože usnadňuje načítání sestavení, zvažte, že vaše aplikace selže s chybovou zprávou, která identifikuje chybějící sestavení, pravděpodobně poskytuje lepší uživatelské prostředí než automatické použití neznámé verze sestavení, což může způsobit nepředvídatelné chování a bezpečnostní díry.

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

Načtení sestavení do více kontextů může způsobit problémy s identitou typu. 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. Vyvolá InvalidCastException se, 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 své identity pomocí Load metody, bude ve výchozím kontextu načítání, a 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. Když teď 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, vyvolá se vyvolá, InvalidCastException protože modul runtime považuje ICommunicate rozhraní ve dvou kopiích Utility sestavení 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 ji použít LoadFrom k 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čítání z kontextu před načtením Utility sestavení vaší aplikace, zatížení aplikace se nezdaří.

V části Zvažte přepnutí na výchozí kontext načtení popisuje alternativy použití cest k souborům, jako je a LoadFromLoadFile .

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

Načtení více verzí sestavení do jednoho kontextu načtení 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. Vyvolá InvalidCastException se, 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é zobrazované názvy sestavení, které obsahují 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. Modul runtime považuje dvě sestavení načtená z různých cest k různým sestavením, 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í této metody můžete AppDomain.GetAssemblies určit, která sestavení se v daném okamžiku načtou.

Zvažte přepnutí na výchozí kontext načtení.

Prozkoumejte vzory načítání sestavení a nasazení vaší aplikace. Můžete eliminovat sestavení, která jsou načtena z bajtových polí? Můžete přesunout sestavení do cesty sondy? 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 jeho identity.

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

Zvažte použití doplňku rozhraní .NET Framework

Pokud k implementaci doplňků používáte kontext z kontextu, které obvykle nejsou nainstalované v základu aplikace, použijte doplně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í mezipaměti 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 k AppDomainSetup vytvoření nové domény aplikace a pomocí AppDomainSetup.ApplicationBase vlastnosti zadejte cestu, která obsahuje sestavení, která chcete načíst. Pokud máte k sondě více adresářů, můžete nastavit ApplicationBase kořenový adresář a pomocí AppDomainSetup.PrivateBinPath vlastnosti identifikovat podadresáře, které se mají testovat. Alternativně můžete vytvořit více domén aplikace a nastavit ApplicationBase každou doménu aplikace na odpovídající cestu pro jeho sestavení.

Všimněte si, že tuto metodu Assembly.LoadFrom můžete použít k načtení těchto sestavení. Vzhledem k tomu, že jsou teď v cestě probírání, budou načteny do výchozího kontextu načítání místo kontextu načítání. 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é