Aanbevolen procedures voor het laden van assembly's
In dit artikel worden manieren besproken om problemen met type identiteiten te voorkomen die kunnen leiden tot InvalidCastExceptionen MissingMethodExceptionmet andere fouten. In het artikel worden de volgende aanbevelingen besproken:
Vermijd het laden van meerdere versies van een assembly in dezelfde context
Overweeg om over te schakelen naar de standaardbelastingscontext
De eerste aanbeveling, inzicht in de voor- en nadelen van belastingcontexten, biedt achtergrondinformatie voor de andere aanbevelingen, omdat ze allemaal afhankelijk zijn van een kennis van belastingcontexten.
Inzicht in de voor- en nadelen van belastingcontexten
In een toepassingsdomein kunnen assembly's worden geladen in een van de drie contexten of kunnen ze zonder context worden geladen:
De standaardbelastingcontext bevat assembly's die zijn gevonden door de globale assemblycache te testen, het assemblyarchief van de host als de runtime wordt gehost (bijvoorbeeld in SQL Server), en het ApplicationBase en PrivateBinPath van het toepassingsdomein. De meeste overbelastingen van de Load methode laden assembly's in deze context.
De load-from-context bevat assembly's die worden geladen vanaf locaties die niet door het laadprogramma worden doorzocht. Invoegtoepassingen kunnen bijvoorbeeld worden geïnstalleerd in een map die zich niet onder het toepassingspad bevindt. Assembly.LoadFrom, AppDomain.CreateInstanceFromen AppDomain.ExecuteAssembly zijn voorbeelden van methoden die per pad worden geladen.
De context met alleen weerspiegeling bevat assembly's die zijn geladen met de ReflectionOnlyLoad en ReflectionOnlyLoadFrom methoden. Code in deze context kan niet worden uitgevoerd, dus deze wordt hier niet besproken. Zie Procedure: Assembly's laden in de Reflection-Only Context voor meer informatie.
Als u een tijdelijke dynamische assembly hebt gegenereerd met behulp van reflectieuitzending, bevindt de assembly zich niet in een context. Bovendien worden de meeste assembly's die worden geladen met behulp van de LoadFile methode zonder context geladen en worden assembly's die vanuit bytematrices worden geladen, zonder context geladen, tenzij hun identiteit (nadat beleid is toegepast) vaststelt dat ze zich in de globale assemblycache bevinden.
De uitvoeringscontexten hebben voor- en nadelen, zoals beschreven in de volgende secties.
Standaardbelastingscontext
Wanneer assembly's in de standaardbelastingscontext worden geladen, worden hun afhankelijkheden automatisch geladen. Afhankelijkheden die in de standaardbelastingscontext worden geladen, worden automatisch gevonden voor assembly's in de standaardbelastingscontext of de load-from-context. Het laden per assembly-identiteit verhoogt de stabiliteit van toepassingen door ervoor te zorgen dat onbekende versies van assembly's niet worden gebruikt (zie de sectie Binding vermijden voor gedeeltelijke assemblynamen ).
Het gebruik van de standaardbelastingcontext heeft de volgende nadelen:
Afhankelijkheden die in andere contexten worden geladen, zijn niet beschikbaar.
U kunt geen assembly's van locaties buiten het testpad laden in de standaardbelastingscontext.
Load-From context
Met de load-from-context kunt u een assembly laden vanuit een pad dat zich niet onder het toepassingspad bevindt en daarom niet is opgenomen in het testen. Hiermee kunnen afhankelijkheden worden gevonden en geladen vanuit dat pad, omdat de padgegevens worden onderhouden door de context. Daarnaast kunnen assembly's in deze context afhankelijkheden gebruiken die in de standaardbelastingscontext worden geladen.
Het laden van assembly's met behulp van de Assembly.LoadFrom methode of een van de andere methoden die per pad worden geladen, heeft de volgende nadelen:
Als een assembly met dezelfde identiteit al in de context van de belasting wordt geladen, wordt de geladen assembly geretourneerd, LoadFrom zelfs als er een ander pad is opgegeven.
Als een assembly wordt geladen met LoadFromen later een assembly in de standaardbelastingscontext probeert dezelfde assembly te laden op weergavenaam, mislukt de belastingspoging. Dit kan gebeuren wanneer een assembly wordt gedeserialiseerd.
Als een assembly wordt geladen met LoadFrom, en het testpad een assembly met dezelfde identiteit bevat, maar op een andere locatie, een InvalidCastException, MissingMethodExceptionof ander onverwacht gedrag kan optreden.
LoadFrom eisen FileIOPermissionAccess.Read en FileIOPermissionAccess.PathDiscovery, of WebPermission, op het opgegeven pad.
Als er een systeemeigen installatiekopieën voor de assembly bestaan, wordt deze niet gebruikt.
De assembly kan niet als domeinneutraal worden geladen.
In de .NET Framework versie 1.0 en 1.1 wordt beleid niet toegepast.
Geen context
Laden zonder context is de enige optie voor tijdelijke assembly's die worden gegenereerd met reflectieuitzending. Laden zonder context is de enige manier om meerdere assembly's met dezelfde identiteit in één toepassingsdomein te laden. De kosten voor het testen worden vermeden.
Assembly's die vanuit bytematrices worden geladen, worden zonder context geladen, tenzij de identiteit van de assembly, die wordt vastgesteld wanneer beleid wordt toegepast, overeenkomt met de identiteit van een assembly in de globale assemblycache; In dat geval wordt de assembly geladen vanuit de globale assemblycache.
Het laden van assembly's zonder context heeft de volgende nadelen:
Andere assembly's kunnen geen binding maken met assembly's die zonder context worden geladen, tenzij u de AppDomain.AssemblyResolve gebeurtenis verwerkt.
Afhankelijkheden worden niet automatisch geladen. U kunt ze vooraf laden zonder context, ze vooraf laden in de standaardbelastingscontext of ze laden door de AppDomain.AssemblyResolve gebeurtenis te verwerken.
Het laden van meerdere assembly's met dezelfde identiteit zonder context kan leiden tot typeidentiteitsproblemen die vergelijkbaar zijn met die veroorzaakt door het laden van assembly's met dezelfde identiteit in meerdere contexten. Zie Voorkomen dat u een assembly in meerdere contexten laadt.
Als er een systeemeigen installatiekopieën voor de assembly bestaan, wordt deze niet gebruikt.
De assembly kan niet als domeinneutraal worden geladen.
In de .NET Framework versie 1.0 en 1.1 wordt beleid niet toegepast.
Binding voorkomen voor gedeeltelijke assemblynamen
Gedeeltelijke naambinding vindt plaats wanneer u alleen een deel van de weergavenaam van de assembly opgeeft (FullName) wanneer u een assembly laadt. U kunt bijvoorbeeld de Assembly.Load methode aanroepen met alleen de eenvoudige naam van de assembly, waarbij u de versie, cultuur en het openbare-sleuteltoken weglaat. Of u kunt de Assembly.LoadWithPartialName methode aanroepen, die eerst de Assembly.Load methode aanroept en, als dat niet lukt om de assembly te vinden, de algemene assemblycache doorzoekt en de meest recente beschikbare versie van de assembly laadt.
Gedeeltelijke naambinding kan veel problemen veroorzaken, waaronder het volgende:
De Assembly.LoadWithPartialName methode kan een andere assembly laden met dezelfde eenvoudige naam. Twee toepassingen kunnen bijvoorbeeld twee volledig verschillende assembly's installeren die beide de eenvoudige naam
GraphicsLibraryhebben in de algemene assemblycache.De assembly die daadwerkelijk is geladen, is mogelijk niet achterwaarts compatibel. Als u bijvoorbeeld niet de versie opgeeft, kan dit leiden tot het laden van een veel latere versie dan de versie die uw programma oorspronkelijk heeft geschreven om te gebruiken. Wijzigingen in de latere versie kunnen fouten veroorzaken in uw toepassing.
De assembly die daadwerkelijk is geladen, is mogelijk niet compatibel met doorsturen. U hebt bijvoorbeeld uw toepassing gebouwd en getest met de nieuwste versie van een assembly, maar gedeeltelijke binding kan een veel eerdere versie laden die geen functies bevat die uw toepassing gebruikt.
Als u nieuwe toepassingen installeert, kunnen bestaande toepassingen worden verbroken. Een toepassing die gebruikmaakt van de LoadWithPartialName methode kan worden verbroken door een nieuwere, niet-compatibele versie van een gedeelde assembly te installeren.
Onverwacht laden van afhankelijkheden kan optreden. Het laden van twee assembly's die een afhankelijkheid delen, het laden ervan met gedeeltelijke binding kan leiden tot één assembly met behulp van een onderdeel waarmee het niet is gebouwd of getest.
Vanwege de problemen die dit kan veroorzaken, is de LoadWithPartialName methode gemarkeerd als verouderd. U wordt aangeraden in plaats daarvan de Assembly.Load methode te gebruiken en volledige assemblyweergavenamen op te geven. Zie Inzicht in de voor- en nadelen van belastingcontexten en overweeg over te schakelen naar de standaardbelastingscontext.
Als u de LoadWithPartialName methode wilt gebruiken omdat het laden van assembly's eenvoudig maakt, kunt u overwegen dat het mislukken van uw toepassing met een foutbericht dat aangeeft dat de ontbrekende assembly waarschijnlijk een betere gebruikerservaring biedt dan automatisch een onbekende versie van de assembly te gebruiken, wat onvoorspelbaar gedrag en beveiligingsgaten kan veroorzaken.
Vermijd het laden van een assembly in meerdere contexten
Het laden van een assembly in meerdere contexten kan identiteitsproblemen veroorzaken. Als hetzelfde type vanuit dezelfde assembly in twee verschillende contexten wordt geladen, is het alsof twee verschillende typen met dezelfde naam zijn geladen. Er wordt een InvalidCastException gegenereerd als u probeert het ene type naar het andere te casten, met het verwarrende bericht dat type MyType niet kan worden gecast naar type MyType.
Stel dat de interface wordt gedeclareerd in een assembly met de ICommunicate naam Utility, waarnaar wordt verwezen door uw programma en ook door andere assembly's die uw programma laadt. Deze andere assembly's bevatten typen die de ICommunicate interface implementeren, zodat uw programma ze kan gebruiken.
Bedenk nu wat er gebeurt wanneer uw programma wordt uitgevoerd. Assembly's waarnaar wordt verwezen door uw programma, worden geladen in de standaardbelastingcontext. Als u een doelassembly laadt op basis van de identiteit, met behulp van de Load methode, bevindt deze zich in de standaardbelastingscontext en zijn de afhankelijkheden. Zowel uw programma als de doelassembly gebruiken dezelfde Utility assembly.
Stel dat u de doelassembly laadt op basis van het bestandspad, met behulp van de LoadFile methode. De assembly wordt zonder context geladen, zodat de afhankelijkheden niet automatisch worden geladen. Mogelijk hebt u een handler voor de AppDomain.AssemblyResolve gebeurtenis om de afhankelijkheid op te geven en kan de Utility assembly zonder context worden geladen met behulp van de LoadFile methode. Wanneer u nu een exemplaar maakt van een type dat is opgenomen in de doelassembly en deze probeert toe te wijzen aan een variabele van het type ICommunicate, wordt er een InvalidCastException gegenereerd omdat de runtime de ICommunicate interfaces in de twee kopieën van de Utility assembly beschouwt als verschillende typen.
Er zijn veel andere scenario's waarin een assembly in meerdere contexten kan worden geladen. De beste methode is om conflicten te voorkomen door de doelassembly in uw toepassingspad te verplaatsen en de methode te gebruiken met de Load volledige weergavenaam. De assembly wordt vervolgens geladen in de standaardbelastingcontext en beide assembly's gebruiken dezelfde Utility assembly.
Als de doelassembly buiten uw toepassingspad moet blijven, kunt u de methode gebruiken om deze LoadFrom te laden in de context van de belasting. Als de doelassembly is gecompileerd met een verwijzing naar de assembly van Utility uw toepassing, wordt de Utility assembly gebruikt die uw toepassing in de standaardbelastingscontext heeft geladen. Houd er rekening mee dat er problemen kunnen optreden als de doelassembly afhankelijk is van een kopie van de Utility assembly die zich buiten uw toepassingspad bevindt. Als deze assembly wordt geladen in de load-from-context voordat uw toepassing de Utility assembly laadt, mislukt de belasting van uw toepassing.
In het gedeelte Overschakelen naar de sectie Standaardbelastingscontext worden alternatieven besproken voor het gebruik van bestandspadbelastingen, zoals LoadFile en LoadFrom.
Vermijd het laden van meerdere versies van een assembly in dezelfde context
Het laden van meerdere versies van een assembly in één laadcontext kan leiden tot identiteitsproblemen van het type. Als hetzelfde type wordt geladen vanuit twee versies van dezelfde assembly, is het alsof twee verschillende typen met dezelfde naam zijn geladen. Er wordt een InvalidCastException gegenereerd als u probeert het ene type naar het andere te casten, met het verwarrende bericht dat type MyType niet kan worden gecast naar type MyType.
Uw programma kan bijvoorbeeld één versie van de Utility assembly rechtstreeks laden en later een andere assembly laden die een andere versie van de Utility assembly laadt. Of een coderingsfout kan ertoe leiden dat twee verschillende codepaden in uw toepassing verschillende versies van een assembly laden.
In de standaardbelastingscontext kan dit probleem optreden wanneer u de Assembly.Load methode gebruikt en volledige assemblyweergavenamen met verschillende versienummers opgeeft. Voor assembly's die zonder context worden geladen, kan het probleem worden veroorzaakt door de Assembly.LoadFile methode te gebruiken om dezelfde assembly uit verschillende paden te laden. De runtime beschouwt twee assembly's die vanuit verschillende paden worden geladen om verschillende assembly's te zijn, zelfs als hun identiteiten hetzelfde zijn.
Naast typeidentiteitsproblemen kunnen meerdere versies van een assembly leiden tot een MissingMethodException als een type dat is geladen uit één versie van de assembly, wordt doorgegeven aan code die verwacht dat type van een andere versie. De code kan bijvoorbeeld een methode verwachten die is toegevoegd aan de latere versie.
Subtielere fouten kunnen optreden als het gedrag van het type tussen versies is gewijzigd. Een methode kan bijvoorbeeld een onverwachte uitzondering genereren of een onverwachte waarde retourneren.
Controleer uw code zorgvuldig om ervoor te zorgen dat slechts één versie van een assembly wordt geladen. U kunt de AppDomain.GetAssemblies methode gebruiken om te bepalen welke assembly's op elk gewenst moment worden geladen.
Overweeg over te schakelen naar de standaardbelastingscontext
Bekijk de assembly-laad- en implementatiepatronen van uw toepassing. Kunt u assembly's verwijderen die uit bytematrices worden geladen? Kunt u assembly's verplaatsen naar het proeftraject? Als assembly's zich in de algemene assemblycache of in het testpad van het toepassingsdomein bevinden (dat wil gezegd, ApplicationBase de bijbehorende en PrivateBinPath), kunt u de assembly laden op basis van de identiteit.
Als het niet mogelijk is om al uw assembly's in het testpad te plaatsen, kunt u alternatieven overwegen, zoals het .NET Framework-invoegtoepassingsmodel gebruiken, assembly's in de algemene assemblycache plaatsen of toepassingsdomeinen maken.
Overweeg het .NET Framework Add-In-model te gebruiken
Als u de load-from-context gebruikt om invoegtoepassingen te implementeren, die doorgaans niet in de toepassingsbasis zijn geïnstalleerd, gebruikt u het .NET Framework invoegtoepassingsmodel. Dit model biedt isolatie op toepassingsdomein- of procesniveau, zonder dat u zelf toepassingsdomeinen hoeft te beheren. Zie Invoegtoepassingen en Uitbreidbaarheid voor informatie over het invoegtoepassingsmodel.
Overweeg het gebruik van de global assembly-cache
Plaats assembly's in de algemene assemblycache om het voordeel te krijgen van een gedeeld assemblypad dat zich buiten de toepassingsbasis bevindt, zonder dat de voordelen van de standaardbelastingscontext verloren gaan of de nadelen van de andere contexten in beslag nemen.
Overweeg het gebruik van toepassingsdomeinen
Als u vaststelt dat sommige assembly's niet kunnen worden geïmplementeerd in het testpad van de toepassing, kunt u overwegen om een nieuw toepassingsdomein voor deze assembly's te maken. Gebruik een AppDomainSetup toepassingsdomein om het nieuwe toepassingsdomein te maken en gebruik de AppDomainSetup.ApplicationBase eigenschap om het pad op te geven dat de assembly's bevat die u wilt laden. Als u meerdere mappen hebt om te testen, kunt u de ApplicationBase map instellen op een hoofdmap en de AppDomainSetup.PrivateBinPath eigenschap gebruiken om de submappen te identificeren die moeten worden gecontroleerd. U kunt ook meerdere toepassingsdomeinen maken en het ApplicationBase toepassingsdomein instellen op het juiste pad voor de assembly's.
Houd er rekening mee dat u de Assembly.LoadFrom methode kunt gebruiken om deze assembly's te laden. Omdat ze zich nu in het testpad bevinden, worden ze geladen in de standaardbelastingscontext in plaats van de load-from-context. We raden u echter aan over te schakelen naar de Assembly.Load methode en volledige assemblyweergavenamen op te geven om ervoor te zorgen dat de juiste versies altijd worden gebruikt.