Metodtips för sammansättningsinläsning

I den här artikeln beskrivs olika sätt att undvika problem med typidentitet 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 inläsningskontexter

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 ApplicationBase och PrivateBinPath för programdomänen. 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 för endast reflektion innehåller sammansättningar som läses in med ReflectionOnlyLoad metoderna och ReflectionOnlyLoadFrom . Kod i den här kontexten kan inte köras, så det beskrivs inte här. Mer information finns i How to: Load Assemblies into the Reflection-Only Context (Så här läser du in sammansättningar i Reflection-Only-kontexten).

  • Om du har genererat en tillfällig dynamisk sammansättning med hjälp av reflektionsavsändaren finns inte sammansättningen i någon kontext. 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 (när 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 säkerställa att okända versioner av sammansättningar inte används (se avsnittet Undvik bindning för 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 avsökningssökvägen till standardinläsningskontexten.

Load-From kontext

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äses in efter sökväg har följande nackdelar:

  • Om en sammansättning med samma identitet redan har lästs in i kontexten load-from LoadFrom returneras 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 försöker en sammansättning i standardinläsningskontexten att läsa in samma sammansättning med visningsnamn, misslyckas inläsningsförsöket. Detta kan inträffa när en sammansättning deserialiseras.

  • Om en sammansättning läses in med LoadFromoch avsökningssökvägen innehåller en sammansättning med samma identitet men på en annan plats kan ett InvalidCastException, MissingMethodExceptioneller annat oväntat beteende uppstå.

  • 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 reflektionsavge. 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 såvida inte sammansättningens identitet, som upprättas när principen tillämpas, matchar identiteten för en sammansättning i den globala sammansättningscache. I så fall läses sammansättningen in från den globala sammansättningscachen.

Att läsa in sammansättningar utan kontext har följande nackdelar:

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

  • 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.

  • Inläsning av flera sammansättningar med samma identitet utan kontext kan 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 sker när du endast anger en del av sammansättningens visningsnamn (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 versionen, kulturen och den offentliga 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 för 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 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ättningen. Se Förstå fördelarna och nackdelarna med inläsningskontexter och överväg att växla till standardinläsningskontexten.

Om du vill använda LoadWithPartialName metoden eftersom det gör det enkelt att läsa in sammansättningen bör du tänka på att om ditt program 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

Inläsning av en sammansättning i flera kontexter kan 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. Ett InvalidCastException utlöses om du försöker omvandla den ena typen till den andra, med det förvirrande meddelandet att typen MyType inte kan konverteras till typen 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 ditt program 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 av Load -metoden, kommer den att finnas i standardinläsningskontexten, och det kommer dess beroenden också 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 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 kontexten load-from. 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 är 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

Om flera versioner av en sammansättning läses in i en belastningskontext kan det orsaka problem med typidentiteten. 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 en typ till den andra, med det förvirrande meddelandet som 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 ditt program 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 anger 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 att använda 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 har ändrats 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 när som helst.

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

Granska programmets sammansättningsmönster för inlä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 avsökningssökvägen kan du överväga alternativ som att använda .NET Framework tilläggsmodell, placera sammansättningar i den globala sammansättningscacheminnet eller skapa programdomäner.

Överväg att använda .NET Framework Add-In-modellen

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äggsmodell. 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 global sammansättningscache

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 andra kontexter.

Överväg att använda programdomäner

Om du fastställer att vissa av dina sammansättningar inte kan distribueras i programmets sökväg för avsökning bör 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 AppDomainSetup.ApplicationBase och använd 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 lämplig 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 sökvägen för avsökning 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 sammansättningsvisningsnamn för att säkerställa att rätt versioner alltid används.

Se även