Megosztás a következőn keresztül:


Ajánlott eljárások a szerelvénybetöltéshez

Feljegyzés

Ez a cikk a .NET-keretrendszer vonatkozik. Ez nem vonatkozik a .NET újabb implementációira, beleértve a .NET 6-os és újabb verzióit.

Ez a cikk bemutatja, hogyan kerülheti el a típusidentitásokkal kapcsolatos problémákat, amelyek a , MissingMethodExceptionés egyéb hibákhoz InvalidCastExceptionvezethetnek. A cikk a következő javaslatokat ismerteti:

Az első javaslat, amely a terhelési környezetek előnyeit és hátrányait ismerteti, háttérinformációkat biztosít a többi javaslathoz, mivel ezek mindegyike a terhelési környezetek ismeretétől függ.

A terhelési környezetek előnyeinek és hátrányainak megismerése

Az alkalmazástartományon belül a szerelvények három környezet egyikébe tölthetők be, vagy környezet nélkül is betölthetők:

  • Az alapértelmezett betöltési környezet tartalmazza a globális szerelvény-gyorsítótár, a gazdagép szerelvénytárolója, ha a futtatókörnyezetet üzemelteti (például az SQL Serverben), valamint az alkalmazástartományt és PrivateBinPath az ApplicationBase alkalmazástartományt. A metódusbetöltési szerelvények legtöbb túlterhelése ebbe a Load kontextusba kerül.

  • A betöltési környezet olyan szerelvényeket tartalmaz, amelyek olyan helyekről töltődnek be, amelyeket a betöltő nem keres. Előfordulhat például, hogy a bővítmények olyan címtárban vannak telepítve, amely nem az alkalmazás elérési útja alatt található. Assembly.LoadFrom, AppDomain.CreateInstanceFromés AppDomain.ExecuteAssembly példák az elérési úton betöltő metódusokra.

  • A csak tükröződési környezet a metódusokkal ReflectionOnlyLoadReflectionOnlyLoadFrom betöltött szerelvényeket tartalmazza. Ebben a környezetben a kód nem hajtható végre, ezért itt nem tárgyaljuk. További információkért lásd : Szerelvények betöltése a csak tükröződési környezetbe.

  • Ha átmeneti dinamikus szerelvényt hozott létre a tükröződés kibocsátásával, a szerelvény nincs semmilyen kontextusban. Emellett a LoadFile metódussal betöltött szerelvények többsége környezet nélkül töltődik be, és a bájttömbökből betöltött szerelvények környezet nélkül töltődnek be, kivéve, ha identitásuk (a szabályzat alkalmazása után) megállapítja, hogy a globális szerelvény-gyorsítótárban vannak.

A végrehajtási környezeteknek vannak előnyei és hátrányai, amint az a következő szakaszokban is szerepel.

Alapértelmezett terhelési környezet

Amikor a szerelvények betöltődnek az alapértelmezett betöltési környezetbe, a rendszer automatikusan betölti a függőségeket. Az alapértelmezett terhelési környezetbe betöltött függőségek automatikusan megtalálhatók az alapértelmezett terhelési környezetben vagy a betöltési környezetben lévő szerelvényeknél. A szerelvények identitása szerinti betöltés növeli az alkalmazások stabilitását azáltal, hogy biztosítja, hogy a szerelvények ismeretlen verziói ne legyenek használatban (lásd a Részleges szerelvénynevek kötésének elkerülése című szakaszt).

Az alapértelmezett terhelési környezet használata a következő hátrányokkal rendelkezik:

  • A más környezetekbe betöltött függőségek nem érhetők el.

  • A próbaútvonalon kívüli helyekről nem tölthet be szerelvényeket az alapértelmezett terhelési környezetbe.

Terhelés a környezetből

A betöltési környezet lehetővé teszi, hogy olyan elérési útról töltsön be egy szerelvényt, amely nincs az alkalmazás elérési útja alatt, ezért nem szerepel a próbakörnyezetben. Lehetővé teszi a függőségek elhelyezését és betöltését ebből az elérési útból, mivel az elérési út adatait a környezet tartja karban. Emellett az ebben a környezetben lévő szerelvények az alapértelmezett betöltési környezetbe betöltött függőségeket is használhatják.

A szerelvények betöltése a Assembly.LoadFrom módszerrel, vagy az útvonal szerint betöltő többi metódus egyikének a következő hátrányai vannak:

  • Ha egy azonos identitással rendelkező szerelvény már be van töltve a betöltési környezetbe, LoadFrom akkor is visszaadja a betöltött szerelvényt, ha más elérési utat adott meg.

  • Ha egy szerelvény be van töltve LoadFrom, és később az alapértelmezett betöltési környezetben egy szerelvény megjelenítendő névvel próbálja betölteni ugyanazt a szerelvényt, a betöltési kísérlet meghiúsul. Ez akkor fordulhat elő, ha egy szerelvény deszerializálva van.

  • Ha egy szerelvény be van töltve LoadFrom, és a próbaútvonal olyan szerelvényt tartalmaz, amely azonos identitással rendelkezik, de egy másik helyen, InvalidCastExceptionelőfordulhat, MissingMethodExceptionhogy váratlan viselkedés történik.

  • LoadFromFileIOPermissionAccess.PathDiscoveryWebPermissionvagy FileIOPermissionAccess.Read a megadott útvonalon.

  • Ha a szerelvényhez natív rendszerkép tartozik, a rendszer nem használja.

  • A szerelvény nem tölthető be tartománysemlegesként.

  • Az .NET-keretrendszer 1.0-s és 1.1-s verzióiban a szabályzat nem lesz alkalmazva.

Nincs környezet

A környezet nélküli betöltés az egyetlen lehetőség a visszaverődéssel létrehozott átmeneti szerelvényekhez. A környezet nélküli betöltés az egyetlen módja annak, hogy több olyan szerelvényt töltsön be, amelyek azonos identitással rendelkeznek egy alkalmazástartományba. A próbaidő költsége elkerülhető.

A bájttömbökből betöltött szerelvények kontextus nélkül töltődnek be, kivéve, ha a szabályzat alkalmazásakor létrehozott szerelvény identitása megegyezik egy szerelvény identitásával a globális szerelvény-gyorsítótárban; ebben az esetben a rendszer betölti a szerelvényt a globális szerelvény-gyorsítótárból.

A szerelvények környezet nélküli betöltése a következő hátrányokkal rendelkezik:

  • Más szerelvények nem köthetők környezet nélkül betöltött szerelvényekhez, kivéve, ha Ön kezeli az eseményt AppDomain.AssemblyResolve .

  • A függőségek nem töltődnek be automatikusan. Előre betöltheti őket környezet nélkül, előre betöltheti őket az alapértelmezett betöltési környezetbe, vagy betöltheti őket az AppDomain.AssemblyResolve esemény kezelésével.

  • Ha több, azonos identitással rendelkező szerelvényt tölt be környezet nélkül, az az azonos identitással rendelkező szerelvények több környezetbe való betöltése által okozott típusidentitás-problémákhoz hasonló típusú identitásproblémákat okozhat. Lásd: Szerelvény betöltése több környezetbe.

  • Ha a szerelvényhez natív rendszerkép tartozik, a rendszer nem használja.

  • A szerelvény nem tölthető be tartománysemlegesként.

  • Az .NET-keretrendszer 1.0-s és 1.1-s verzióiban a szabályzat nem lesz alkalmazva.

A részleges szerelvénynevek kötésének elkerülése

Részleges névkötés akkor fordul elő, ha a szerelvény betöltésekor a szerelvény megjelenítendő nevének (FullName) csak egy részét adja meg. Meghívhatja például a Assembly.Load metódust csak a szerelvény egyszerű nevével, kihagyva a verziót, a kultúrát és a nyilvános kulcs jogkivonatát. Vagy meghívhatja a Assembly.LoadWithPartialName metódust, amely először meghívja a Assembly.Load metódust, és ha ez nem találja a szerelvényt, megkeresi a globális szerelvény gyorsítótárát, és betölti a szerelvény legújabb elérhető verzióját.

A részleges névkötés számos problémát okozhat, többek között az alábbiakat:

  • Előfordulhat, hogy a Assembly.LoadWithPartialName metódus egy másik szerelvényt tölt be ugyanazzal az egyszerű névvel. Két alkalmazás például két teljesen különböző szerelvényt telepíthet, amelyek mindegyike egyszerű nevet GraphicsLibrary ad a globális szerelvény-gyorsítótárnak.

  • Előfordulhat, hogy a ténylegesen betöltött szerelvény nem kompatibilis visszamenőlegesen. Ha például nem adja meg a verziót, az egy sokkal későbbi verzió betöltését eredményezheti, mint a program eredetileg használni kívánt verziója. A későbbi verzió módosításai hibákat okozhatnak az alkalmazásban.

  • Előfordulhat, hogy a ténylegesen betöltött szerelvény nem lesz továbbítható. Előfordulhat például, hogy az alkalmazást egy szerelvény legújabb verziójával hozta létre és tesztelte, de a részleges kötés betölthet egy sokkal korábbi verziót, amely nem rendelkezik az alkalmazás által használt funkciókkal.

  • Az új alkalmazások telepítése megszakíthatja a meglévő alkalmazásokat. A metódust használó LoadWithPartialName alkalmazások megszakadhatnak egy megosztott szerelvény újabb, nem kompatibilis verziójának telepítésével.

  • Váratlan függőségbetöltés történhet. Két, függőséggel rendelkező szerelvényt tölt be, és részleges kötéssel való betöltése egy szerelvényt eredményezhet egy olyan összetevő használatával, amellyel nem készült vagy tesztelt.

Az általa okozott problémák miatt a LoadWithPartialName metódus elavultnak lett jelölve. Javasoljuk, hogy inkább a metódust Assembly.Load használja, és adja meg a teljes szerelvénymegjelenítési neveket. Tekintse meg a terhelési környezetek előnyeit és hátrányait , és fontolja meg az alapértelmezett terhelési környezetre való váltást.

Ha a LoadWithPartialName metódust azért szeretné használni, mert megkönnyíti a szerelvény betöltését, vegye figyelembe, hogy az alkalmazás sikertelensége esetén egy hibaüzenet jelzi, hogy a hiányzó szerelvény valószínűleg jobb felhasználói élményt nyújt, mint a szerelvény ismeretlen verziójának automatikus használata, ami kiszámíthatatlan viselkedést és biztonsági lyukakat okozhat.

Ne töltsünk be egy szerelvényt több környezetbe

Egy szerelvény több környezetbe való betöltése típusidentitási problémákat okozhat. Ha ugyanabból a szerelvényből két különböző környezetbe tölti be ugyanazt a típust, az olyan, mintha két azonos nevű típus lett volna betöltve. A rendszer akkor küldi el az egyik InvalidCastException típust a másiknak, ha zavaró üzenetet küld, hogy a típus MyType nem írható be MyType.

Tegyük fel például, hogy az ICommunicate interfész egy nevesített Utilityszerelvényben van deklarálva, amelyre a program hivatkozik, valamint a program által betöltött egyéb szerelvényekre is. Ezek a többi szerelvények olyan típusokat tartalmaznak, amelyek implementálják az ICommunicate interfészt, így a program használhatja őket.

Most gondolja át, mi történik a program futtatásakor. A program által hivatkozott szerelvények az alapértelmezett betöltési környezetbe töltődnek be. Ha egy célszerelvényt az identitása alapján tölt be a Load metódus használatával, az az alapértelmezett betöltési környezetben lesz, és a függőségei is. A program és a célszerelvény is ugyanazt Utility a szerelvényt fogja használni.

Tegyük fel azonban, hogy a metódus használatával betölti a célszerelvényt a LoadFile fájl elérési útján. A szerelvény környezet nélkül van betöltve, így a rendszer nem tölti be automatikusan a függőségeit. Előfordulhat, hogy az AppDomain.AssemblyResolve eseményhez van egy kezelője, amely biztosítja a függőséget, és a metódus használatával környezet nélkül töltheti be Utility a szerelvényt LoadFile . Most, amikor létrehoz egy példányt egy olyan típusból, amely a célszerelvényben található, és megpróbálja hozzárendelni egy típus ICommunicateváltozójához, InvalidCastException a futtatókörnyezet különböző típusúnak tekinti ICommunicate a Utility szerelvény két példányában található interfészeket.

Számos más forgatókönyv is létezik, amelyekben egy szerelvény több környezetbe is betölthető. A legjobb módszer az ütközések elkerülése, ha áthelyezi a célszerelvényt az alkalmazás elérési útján, és a Load metódust használja a teljes megjelenítendő névvel. A rendszer ezután betölti a szerelvényt az alapértelmezett terhelési környezetbe, és mindkét szerelvények ugyanazt a szerelvényt Utility használják.

Ha a célszerelvénynek kívül kell maradnia az alkalmazás elérési útján, a LoadFrom metódus használatával betöltheti a betöltési környezetbe. Ha a célszerelvényt az alkalmazás szerelvényére Utility mutató hivatkozással állították össze, azt a Utility szerelvényt fogja használni, amelyet az alkalmazás betöltött az alapértelmezett betöltési környezetbe. Vegye figyelembe, hogy problémák akkor fordulhatnak elő, ha a célszerelvény függ az Utility alkalmazás elérési útján kívül található szerelvény egy példányától. Ha a szerelvény betöltődik a terhelési környezetbe, mielőtt az alkalmazás betöltené a Utility szerelvényt, az alkalmazás terhelése sikertelen lesz.

Az Alapértelmezett betöltési környezetre váltás lehetőség című szakasz a fájlelérési út betöltésének alternatíváit ismerteti, például LoadFile az és LoadFroma .

Kerülje a szerelvény több verziójának betöltését ugyanabba a környezetbe

Egy szerelvény több verziójának betöltése egy betöltési környezetbe típusidentitás-problémákat okozhat. Ha ugyanazt a típust ugyanazon szerelvény két verziójából tölti be, az olyan, mintha két azonos nevű különböző típus lett volna betöltve. A rendszer akkor küldi el az egyik InvalidCastException típust a másiknak, ha zavaró üzenetet küld, hogy a típus MyType nem írható be MyType.

Előfordulhat például, hogy a program közvetlenül betölti a Utility szerelvény egyik verzióját, később pedig betölt egy másik szerelvényt, amely betölti a Utility szerelvény egy másik verzióját. Vagy kódolási hiba okozhatja, hogy az alkalmazásban két különböző kódútvonal töltődik be egy szerelvény különböző verzióival.

Az alapértelmezett betöltési környezetben ez a probléma akkor fordulhat elő, ha a metódust használja, és megadja a Assembly.Load különböző verziószámokat tartalmazó teljes szerelvénymegjelenítési neveket. A környezet nélkül betöltött szerelvények esetében a problémát az okozhatja, hogy a Assembly.LoadFile metódussal ugyanazt a szerelvényt különböző útvonalakról tölti be. A futtatókörnyezet a különböző útvonalakról betöltött két szerelvényeket eltérő szerelvényeknek tekinti, még akkor is, ha azonosak az identitásuk.

A típusidentitási problémák mellett a szerelvény több verziója is okozhat MissingMethodException olyan típust, amely a szerelvény egyik verziójából töltődik be olyan kódnak, amely az adott típust egy másik verziótól várja. Előfordulhat például, hogy a kód egy metódust vár, amelyet hozzáadtak a későbbi verzióhoz.

Finomabb hibák akkor fordulhatnak elő, ha a típus viselkedése a verziók között megváltozott. Előfordulhat például, hogy egy metódus váratlan kivételt jelez, vagy váratlan értéket ad vissza.

Gondosan tekintse át a kódot, hogy a szerelvénynek csak egy verziója legyen betöltve. Ezzel a AppDomain.GetAssemblies módszerrel meghatározhatja, hogy mely szerelvények tölthetők be egy adott időpontban.

Fontolja meg az alapértelmezett terhelési környezetre való váltást

Vizsgálja meg az alkalmazás szerelvénybetöltési és üzembehelyezési mintáit. Meg tudja szüntetni a bájttömbökből betöltött szerelvényeket? Át tudja helyezni a szerelvényeket a próbaútra? Ha a szerelvények a globális szerelvénygyorsítótárban vagy az alkalmazástartomány próbaútvonalán (azaz annak ésPrivateBinPath) találhatók, ApplicationBase a szerelvényt az identitása alapján töltheti be.

Ha nem lehet az összes szerelvényt a próbaútvonalba helyezni, fontolja meg az olyan alternatív megoldásokat, mint a .NET-keretrendszer bővítménymodell használata, szerelvények elhelyezése a globális szerelvény-gyorsítótárban vagy alkalmazástartományok létrehozása.

Fontolja meg a .NET-keretrendszer bővítménymodell használatát

Ha a betöltési környezetet használja a bővítmények implementálásához, amelyek általában nincsenek telepítve az alkalmazásbázisban, használja a .NET-keretrendszer bővítménymodellt. Ez a modell elkülönítést biztosít az alkalmazástartomány vagy a folyamat szintjén anélkül, hogy saját maga kellene kezelnie az alkalmazástartományokat. A bővítménymodellről további információt a Bővítmények és bővíthetőség című témakörben talál.

Fontolja meg a globális szerelvény-gyorsítótár használatát

Helyezze a szerelvényeket a globális szerelvény-gyorsítótárba, hogy kihasználhassa az alkalmazásbázison kívüli megosztott szerelvényútvonal előnyeit anélkül, hogy elveszítené az alapértelmezett terhelési környezet előnyeit, vagy kihasználhatja a többi környezet hátrányait.

Fontolja meg az alkalmazástartományok használatát

Ha úgy ítéli meg, hogy egyes szerelvények nem helyezhetők üzembe az alkalmazás próbaútvonalán, érdemes lehet létrehozni egy új alkalmazástartományt ezekhez a szerelvényekhez. Az an AppDomainSetup használatával hozza létre az új alkalmazástartományt, és a AppDomainSetup.ApplicationBase tulajdonság használatával adja meg a betölteni kívánt szerelvények elérési útját. Ha több könyvtárat szeretne mintavételezni, beállíthatja a ApplicationBase gyökérkönyvtárat, és a AppDomainSetup.PrivateBinPath tulajdonság használatával azonosíthatja a mintavételhez használt alkönyvtárakat. Másik lehetőségként több alkalmazástartományt is létrehozhat, és az ApplicationBase egyes alkalmazástartományokat a szerelvények megfelelő elérési útjára állíthatja.

Vegye figyelembe, hogy a módszerrel betöltheti ezeket a Assembly.LoadFrom szerelvényeket. Mivel most már a próbaútvonalon vannak, a rendszer betölti őket az alapértelmezett terhelési környezetbe a betöltési környezet helyett. Javasoljuk azonban, hogy váltson a metódusra, és adja meg a Assembly.Load teljes szerelvénymegjelenítési neveket, hogy mindig a megfelelő verziókat használják.

Lásd még