Dela via


Metodtips för sammansättningsinläsning

Kommentar

Den här artikeln är specifik för .NET Framework. Det gäller inte för nyare implementeringar av .NET, inklusive .NET 6 och senare versioner.

I den här artikeln beskrivs olika sätt att undvika problem av typen identitet som kan leda till InvalidCastException, MissingMethodExceptionoch andra fel. I artikeln beskrivs följande rekommendationer:

Den första rekommendationen, förstå fördelarna och nackdelarna med belastningskontexter, ger bakgrundsinformation för de andra rekommendationerna, eftersom alla är beroende av kunskap om belastningskontexter.

Förstå fördelarna och nackdelarna med belastningskontexter

I en programdomän kan sammansättningar läsas in i någon av tre kontexter, eller läsas in utan kontext:

  • Standardinläsningskontexten innehåller sammansättningar som hittas genom att avsöka den globala sammansättningscachen, värdsammansättningsarkivet om körningen finns (till exempel i SQL Server) och programdomänen ApplicationBase och PrivateBinPath . De flesta överlagringar av Load metoden läser in sammansättningar i den här kontexten.

  • Inläsningskontexten innehåller sammansättningar som läses in från platser som inte genomsöks av inläsaren. Till exempel kan tillägg installeras i en katalog som inte finns under programsökvägen. Assembly.LoadFrom, AppDomain.CreateInstanceFromoch AppDomain.ExecuteAssembly är exempel på metoder som läses in efter sökväg.

  • Kontexten endast reflektion innehåller sammansättningar som läses in med ReflectionOnlyLoad metoderna och ReflectionOnlyLoadFrom . Det går inte att köra kod i den här kontexten, så den beskrivs inte här. Mer information finns i How to: Load Assemblies into the Reflection-Only Context (Läs in sammansättningar i kontexten Endast reflektion).

  • Om du genererade en tillfällig dynamisk sammansättning med hjälp av reflektionsemittenten finns sammansättningen inte i något sammanhang. Dessutom läses de flesta sammansättningar som läses in med hjälp LoadFile av metoden in utan kontext, och sammansättningar som läses in från bytematriser läses in utan kontext om inte deras identitet (efter att principen har tillämpats) anger att de finns i den globala sammansättningscachen.

Körningskontexterna har fördelar och nackdelar, enligt beskrivningen i följande avsnitt.

Standardinläsningskontext

När sammansättningar läses in i standardinläsningskontexten läses deras beroenden in automatiskt. Beroenden som läses in i standardinläsningskontexten hittas automatiskt för sammansättningar i standardinläsningskontexten eller inläsningskontexten. Inläsning efter sammansättningsidentitet ökar stabiliteten för program genom att se till att okända versioner av sammansättningar inte används (se avsnittet Undvik bindning på partiella sammansättningsnamn ).

Användning av standardinläsningskontexten har följande nackdelar:

  • Beroenden som läses in i andra kontexter är inte tillgängliga.

  • Du kan inte läsa in sammansättningar från platser utanför sökvägen för avsökning till standardinläsningskontexten.

Inläsningskontext

Med inläsningskontexten kan du läsa in en sammansättning från en sökväg som inte finns under programsökvägen och därför inte ingår i avsökningen. Det gör att beroenden kan lokaliseras och läsas in från den sökvägen, eftersom sökvägsinformationen underhålls av kontexten. Dessutom kan sammansättningar i den här kontexten använda beroenden som läses in i standardinläsningskontexten.

Att läsa in sammansättningar med hjälp Assembly.LoadFrom av metoden, eller någon av de andra metoderna som läser in efter sökväg, har följande nackdelar:

  • Om en sammansättning med samma identitet redan har lästs in i inläsningskontexten LoadFrom returnerar den inlästa sammansättningen även om en annan sökväg har angetts.

  • Om en sammansättning läses in med LoadFrom, och senare en sammansättning i standardinläsningskontexten försöker läsa in samma sammansättning med visningsnamn, misslyckas belastningsförsöket. Detta kan inträffa när en sammansättning deserialiseras.

  • Om en sammansättning läses in med LoadFrom, och sökvägen för avsökning innehåller en sammansättning med samma identitet, men på en annan plats, kan ett InvalidCastException, MissingMethodExceptioneller annat oväntat beteende inträffa.

  • LoadFrom krav FileIOPermissionAccess.Read och FileIOPermissionAccess.PathDiscovery, eller WebPermission, på den angivna sökvägen.

  • Om det finns en intern avbildning för sammansättningen används den inte.

  • Sammansättningen kan inte läsas in som domänneutral.

  • I .NET Framework-versionerna 1.0 och 1.1 tillämpas inte principen.

Ingen kontext

Inläsning utan kontext är det enda alternativet för tillfälliga sammansättningar som genereras med reflektionsavgivande. Inläsning utan kontext är det enda sättet att läsa in flera sammansättningar som har samma identitet i en programdomän. Kostnaden för avsökning undviks.

Sammansättningar som läses in från bytematriser läses in utan kontext om inte sammansättningens identitet, som upprättas när principen tillämpas, matchar identiteten för en sammansättning i den globala sammansättningscachen. I så fall läses sammansättningen in från den globala sammansättningscacheminnet.

Inläsning av sammansättningar utan kontext har följande nackdelar:

  • Andra sammansättningar kan inte binda till sammansättningar som läses in utan kontext, såvida du inte hanterar händelsen AppDomain.AssemblyResolve .

  • Beroenden läses inte in automatiskt. Du kan förinstallera dem utan kontext, förinstallera dem i standardinläsningskontexten eller läsa in dem genom att AppDomain.AssemblyResolve hantera händelsen.

  • Om du läser in flera sammansättningar med samma identitet utan kontext kan det orsaka typidentitetsproblem som liknar dem som orsakas av inläsning av sammansättningar med samma identitet i flera kontexter. Se Undvik att läsa in en sammansättning i flera kontexter.

  • Om det finns en intern avbildning för sammansättningen används den inte.

  • Sammansättningen kan inte läsas in som domänneutral.

  • I .NET Framework-versionerna 1.0 och 1.1 tillämpas inte principen.

Undvik bindning för partiella sammansättningsnamn

Partiell namnbindning inträffar när du endast anger en del av sammansättningsvisningsnamnet (FullName) när du läser in en sammansättning. Du kan till exempel anropa Assembly.Load metoden med endast det enkla namnet på sammansättningen och utelämna version, kultur och offentlig nyckeltoken. Eller så kan du anropa Assembly.LoadWithPartialName metoden, som först anropar Assembly.Load metoden och, om det inte går att hitta sammansättningen, söker i den globala sammansättningscacheminnet och läser in den senaste tillgängliga versionen av sammansättningen.

Partiell namnbindning kan orsaka många problem, inklusive följande:

  • Metoden Assembly.LoadWithPartialName kan läsa in en annan sammansättning med samma enkla namn. Två program kan till exempel installera två helt olika sammansättningar som båda har det enkla namnet GraphicsLibrary i den globala sammansättningscachen.

  • Sammansättningen som faktiskt läses in kanske inte är bakåtkompatibel. Om du till exempel inte anger versionen kan det leda till att en mycket senare version läses in än den version som programmet ursprungligen skrevs att använda. Ändringar i den senare versionen kan orsaka fel i ditt program.

  • Sammansättningen som faktiskt läses in kanske inte är framåtkompatibel. Du kan till exempel ha skapat och testat ditt program med den senaste versionen av en sammansättning, men partiell bindning kan läsa in en mycket tidigare version som saknar funktioner som programmet använder.

  • Installation av nya program kan bryta befintliga program. Ett program som använder LoadWithPartialName metoden kan brytas genom att installera en nyare, inkompatibel version av en delad sammansättning.

  • Oväntad inläsning av beroenden kan inträffa. Om du läser in två sammansättningar som delar ett beroende kan inläsning av dem med partiell bindning resultera i en sammansättning med hjälp av en komponent som den inte har skapats eller testats med.

På grund av de problem som den kan orsaka LoadWithPartialName har metoden markerats som föråldrad. Vi rekommenderar att du använder Assembly.Load metoden i stället och anger fullständiga visningsnamn för sammansättning. Se Förstå fördelarna och nackdelarna med belastningskontexter och överväg att växla till standardinläsningskontexten.

Om du vill använda LoadWithPartialName metoden eftersom den gör monteringsinläsningen enkel bör du tänka på att om programmet misslyckas med ett felmeddelande som identifierar den saknade sammansättningen kan det ge en bättre användarupplevelse än att automatiskt använda en okänd version av sammansättningen, vilket kan orsaka oförutsägbart beteende och säkerhetshål.

Undvik att läsa in en sammansättning i flera kontexter

Om du läser in en sammansättning i flera kontexter kan det orsaka typidentitetsproblem. Om samma typ läses in från samma sammansättning i två olika kontexter är det som om två olika typer med samma namn hade lästs in. En InvalidCastException utlöses om du försöker casta den ena typen till den andra, med det förvirrande meddelandet att typen MyType inte kan castas för att skriva MyType.

Anta till exempel att ICommunicate gränssnittet deklareras i en sammansättning med namnet Utility, som refereras av ditt program och även av andra sammansättningar som programmet läser in. Dessa andra sammansättningar innehåller typer som implementerar ICommunicate gränssnittet så att programmet kan använda dem.

Tänk nu på vad som händer när programmet körs. Sammansättningar som refereras av ditt program läses in i standardinläsningskontexten. Om du läser in en målsammansättning med dess identitet, med hjälp Load av metoden, kommer den att finnas i standardinläsningskontexten, och det kommer även dess beroenden att göra. Både programmet och målsammansättningen använder samma Utility sammansättning.

Anta dock att du läser in målsammansättningen med dess filsökväg med hjälp av LoadFile metoden . Sammansättningen läses in utan någon kontext, så dess beroenden läses inte in automatiskt. Du kan ha en hanterare för händelsen för AppDomain.AssemblyResolve att ange beroendet, och den kan läsa in Utility sammansättningen utan kontext med hjälp LoadFile av metoden. Nu när du skapar en instans av en typ som finns i målsammansättningen och försöker tilldela den till en variabel av typen ICommunicate, genereras en InvalidCastException eftersom körningen anser att gränssnitten ICommunicate i de två kopiorna av Utility sammansättningen är olika typer.

Det finns många andra scenarier där en sammansättning kan läsas in i flera kontexter. Den bästa metoden är att undvika konflikter genom att flytta målsammansättningen i programsökvägen och använda Load metoden med det fullständiga visningsnamnet. Sammansättningen läses sedan in i standardinläsningskontexten och båda sammansättningarna använder samma Utility sammansättning.

Om målsammansättningen måste ligga utanför programsökvägen kan du använda LoadFrom metoden för att läsa in den i inläsningskontexten. Om målsammansättningen kompilerades med en referens till programmets Utility sammansättning använder den Utility sammansättning som programmet har läst in i standardinläsningskontexten. Observera att problem kan uppstå om målsammansättningen har ett beroende av en kopia av Utility sammansättningen som finns utanför programsökvägen. Om sammansättningen läses in i inläsningskontexten Utility innan programmet läser in sammansättningen misslyckas programmets belastning.

I avsnittet Överväg att växla till standardinläsningskontexten beskrivs alternativ till att använda filsökvägsinläsningar som LoadFile och LoadFrom.

Undvik att läsa in flera versioner av en sammansättning i samma kontext

Att läsa in flera versioner av en sammansättning i en belastningskontext kan orsaka typidentitetsproblem. Om samma typ läses in från två versioner av samma sammansättning är det som om två olika typer med samma namn hade lästs in. En InvalidCastException utlöses om du försöker casta den ena typen till den andra, med det förvirrande meddelandet att typen MyType inte kan castas för att skriva MyType.

Programmet kan till exempel läsa in en version av Utility sammansättningen direkt och senare kan den läsa in en annan sammansättning som läser in en annan version av Utility sammansättningen. Eller så kan ett kodfel orsaka att två olika kodsökvägar i programmet läser in olika versioner av en sammansättning.

I standardinläsningskontexten kan det här problemet uppstå när du använder Assembly.Load metoden och ange fullständiga visningsnamn för sammansättning som innehåller olika versionsnummer. För sammansättningar som läses in utan kontext kan problemet orsakas av Assembly.LoadFile metoden för att läsa in samma sammansättning från olika sökvägar. Körningen anser att två sammansättningar som läses in från olika sökvägar är olika sammansättningar, även om deras identiteter är desamma.

Förutom typidentitetsproblem kan flera versioner av en sammansättning orsaka en MissingMethodException om en typ som läses in från en version av sammansättningen skickas till kod som förväntar sig den typen från en annan version. Koden kan till exempel förvänta sig en metod som har lagts till i den senare versionen.

Mer subtila fel kan inträffa om beteendet för typen ändras mellan versioner. En metod kan till exempel utlösa ett oväntat undantag eller returnera ett oväntat värde.

Granska koden noggrant för att se till att endast en version av en sammansättning läses in. Du kan använda AppDomain.GetAssemblies metoden för att avgöra vilka sammansättningar som läses in vid en viss tidpunkt.

Överväg att växla till standardinläsningskontexten

Granska programmets mönster för sammansättningsinläsning och distribution. Kan du eliminera sammansättningar som läses in från bytematriser? Kan du flytta sammansättningar till sökvägen för avsökning? Om sammansättningar finns i den globala sammansättningscacheminnet eller i programdomänens avsökningssökväg (dvs. dess ApplicationBase och PrivateBinPath), kan du läsa in sammansättningen med dess identitet.

Om det inte går att placera alla sammansättningar i sökvägen för avsökning kan du överväga alternativ som att använda .NET Framework-tilläggsmodellen, placera sammansättningar i den globala sammansättningscacheminnet eller skapa programdomäner.

Överväg att använda .NET Framework-tilläggsmodellen

Om du använder inläsningskontexten för att implementera tillägg, som vanligtvis inte är installerade i programbasen, använder du .NET Framework-tilläggsmodellen. Den här modellen tillhandahåller isolering på programdomän eller processnivå, utan att du behöver hantera programdomäner själv. Information om tilläggsmodellen finns i Tillägg och Utökningsbarhet.

Överväg att använda den globala sammansättningscachen

Placera sammansättningar i den globala sammansättningscacheminnet för att få nytta av en delad sammansättningssökväg som ligger utanför programbasen, utan att förlora fördelarna med standardinläsningskontexten eller utnyttja nackdelarna med de andra kontexterna.

Överväg att använda programdomäner

Om du bedömer att vissa av dina sammansättningar inte kan distribueras i programmets avsökningssökväg kan du överväga att skapa en ny programdomän för dessa sammansättningar. Använd en AppDomainSetup för att skapa den nya programdomänen och använd AppDomainSetup.ApplicationBase egenskapen för att ange sökvägen som innehåller de sammansättningar som du vill läsa in. Om du har flera kataloger att avsöka kan du ange ApplicationBase till en rotkatalog och använda AppDomainSetup.PrivateBinPath egenskapen för att identifiera de underkataloger som ska avsökas. Du kan också skapa flera programdomäner och ange ApplicationBase för varje programdomän till rätt sökväg för dess sammansättningar.

Observera att du kan använda Assembly.LoadFrom metoden för att läsa in dessa sammansättningar. Eftersom de nu är i avsökningssökvägen läses de in i standardinläsningskontexten i stället för inläsningskontexten. Vi rekommenderar dock att du växlar till Assembly.Load metoden och anger fullständiga visningsnamn för sammansättning för att säkerställa att rätt versioner alltid används.

Se även