Aanbevolen procedures voor het laden van assembly's
Notitie
Dit artikel is specifiek voor .NET Framework. Dit geldt niet voor nieuwere implementaties van .NET, waaronder .NET 6 en nieuwere versies.
In dit artikel worden manieren besproken om problemen met typeidentiteit te voorkomen die kunnen leiden tot InvalidCastException, MissingMethodExceptionen andere fouten. In het artikel worden de volgende aanbevelingen besproken:
Vermijd het laden van meerdere versies van een assembly in dezelfde context
Overweeg 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
Binnen een toepassingsdomein kunnen assembly's worden geladen in een van de drie contexten, of ze kunnen zonder context worden geladen:
De standaardbelastingcontext bevat assembly's die zijn gevonden door de algemene assemblycache te testen, het hostassemblyarchief als de runtime wordt gehost (bijvoorbeeld in SQL Server) en het ApplicationBase en PrivateBinPath 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 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 Instructies voor meer informatie : Assembly's laden in de context alleen weerspiegeling.
Als u een tijdelijke dynamische assembly hebt gegenereerd met behulp van weerspiegelingsuitzending, bevindt de assembly zich niet in een context. Bovendien worden de meeste assembly's die worden geladen met behulp van de LoadFile methode, geladen zonder context en worden assembly's die vanuit bytematrices worden geladen zonder context, 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 context van de belasting. 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 laden vanaf locaties buiten het testpad in de standaardbelastingscontext.
Laden vanuit context
Met de context laden vanuit de 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 standaard laadcontext probeert dezelfde assembly te laden op weergavenaam, mislukt de laadpoging. 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 .NET Framework-versies 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 reflectie-emit. Laden zonder context is de enige manier om meerdere assembly's met dezelfde identiteit in één toepassingsdomein te laden. De kosten van het testen worden vermeden.
Assembly's die vanuit bytematrices worden geladen zonder context, 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 afhandelt.
Afhankelijkheden worden niet automatisch geladen. U kunt ze vooraf laden zonder context, ze vooraf laden in de standaard laadcontext of 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 Vermijd het laden van een assembly in meerdere contexten.
Als er een systeemeigen installatiekopieën voor de assembly bestaan, wordt deze niet gebruikt.
De assembly kan niet als domeinneutraal worden geladen.
In .NET Framework-versies 1.0 en 1.1 wordt beleid niet toegepast.
Binding op gedeeltelijke assemblynamen voorkomen
Gedeeltelijke naambinding vindt plaats wanneer u slechts 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 de versie, cultuur en het openbare-sleuteltoken worden weggelaten. U kunt ook de Assembly.LoadWithPartialName methode aanroepen, die eerst de Assembly.Load methode aanroept en, als de assembly niet kan worden gevonden, de algemene assemblycache doorzoekt en de meest recente beschikbare versie van de assembly laadt.
Gedeeltelijke naambinding kan veel problemen veroorzaken, waaronder de 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
GraphicsLibrary
hebben in de algemene assemblycache.De assembly die daadwerkelijk wordt 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 voor gebruik. Wijzigingen in de latere versie kunnen fouten in uw toepassing veroorzaken.
De assembly die daadwerkelijk wordt geladen, is mogelijk niet doorsturen compatibel. 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 door uw toepassing worden 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. Als u twee assembly's laadt die een afhankelijkheid delen, kan het laden ervan met gedeeltelijke binding leiden tot één assembly met behulp van een onderdeel waarmee deze niet is gebouwd of getest.
Vanwege de problemen die het 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 standaardbelastingcontext.
Als u de LoadWithPartialName methode wilt gebruiken omdat het laden van assembly's eenvoudig maakt, kunt u overwegen dat uw toepassing mislukt met een foutbericht waarin wordt aangegeven 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.
Voorkom dat een assembly in meerdere contexten wordt geladen
Het laden van een assembly in meerdere contexten kan leiden tot identiteitsproblemen van het type. Als hetzelfde type vanuit dezelfde assembly in twee verschillende contexten wordt geladen, is het alsof twee verschillende typen met dezelfde naam zijn geladen. Er InvalidCastException wordt een 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 door het programma worden geladen. 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 in de standaardbelastingscontext geladen. Als u een doelassembly laadt op basis van de identiteit, met behulp van de Load methode, bevindt deze zich in de standaardbelastingcontext 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 aanpak is om conflicten te voorkomen door de doelassembly in uw toepassingspad te verplaatsen en de Load methode te gebruiken met de volledige weergavenaam. De assembly wordt vervolgens in de standaardbelastingscontext geladen en beide assembly's gebruiken dezelfde Utility
assembly.
Als de doelassembly buiten uw toepassingspad moet blijven, kunt u de LoadFrom methode gebruiken om deze 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 het 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 de sectie 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 problemen met de typeidentiteit veroorzaken. Als hetzelfde type wordt geladen vanuit twee versies van dezelfde assembly, is het alsof er twee verschillende typen met dezelfde naam zijn geladen. Er InvalidCastException wordt een 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 vanuit één versie van de assembly wordt doorgegeven aan code die verwacht dat type afkomstig is van een andere versie. De code kan bijvoorbeeld een methode verwachten die is toegevoegd aan de latere versie.
Er kunnen subtielere fouten 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, het bijbehorende ApplicationBase en PrivateBinPath), kunt u de assembly laden op basis van de identiteit.
Als het niet mogelijk is om al uw assembly's in het proefpad te plaatsen, kunt u alternatieven overwegen, zoals het .NET Framework-invoegtoepassingsmodel gebruiken, assembly's in de globale assemblycache plaatsen of toepassingsdomeinen maken.
Overweeg het .NET Framework-invoegtoepassingsmodel 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 meer informatie over het invoegtoepassingsmodel.
Overweeg het gebruik van de global assembly-cache
Plaats assembly's in de globale assemblycache om het voordeel te krijgen van een gedeeld assemblypad dat zich buiten de toepassingsbasis bevindt, zonder dat de voordelen van de standaardbelastingcontext verloren gaan of de nadelen van de andere contexten in beslag nemen.
Overweeg het gebruik van toepassingsdomeinen
Als u vaststelt dat sommige van uw assembly's niet kunnen worden geïmplementeerd in het testpad van de toepassing, kunt u overwegen 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 die u wilt testen, kunt u de ApplicationBase map instellen op een hoofdmap en de AppDomainSetup.PrivateBinPath eigenschap gebruiken om de submappen te identificeren die u wilt testen. U kunt ook meerdere toepassingsdomeinen maken en het ApplicationBase toepassingsdomein instellen op het juiste pad voor de bijbehorende 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 in de standaardbelastingscontext geladen in plaats van de context van de belasting. 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.