Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of mappen te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen om mappen te wijzigen.
.NET biedt de AppDomain.AssemblyResolve gebeurtenis voor toepassingen waarvoor meer controle nodig is over het laden van assembly's. Door deze gebeurtenis te verwerken, kan uw toepassing een assembly laden in de laadcontext van buiten de normale testpaden, selecteren welke van verschillende assemblyversies moeten worden geladen, een dynamische assembly verzenden en deze retourneren, enzovoort. Dit onderwerp bevat richtlijnen voor het afhandelen van de AssemblyResolve gebeurtenis.
Opmerking
Gebruik in plaats daarvan het AppDomain.ReflectionOnlyAssemblyResolve-evenement om assembly-loads op te lossen in de context die alleen voor reflectie geldt.
Hoe de AssemblyResolve-gebeurtenis werkt
Wanneer u een handler registreert voor de AssemblyResolve gebeurtenis, wordt de handler aangeroepen wanneer de runtime niet op naam aan een assembly kan worden gebonden. Als u bijvoorbeeld de volgende methoden aanroept vanuit gebruikerscode, kan dit ertoe leiden dat de AssemblyResolve gebeurtenis wordt gegenereerd:
Een AppDomain.Load methode-overbelasting of Assembly.Load methode-overbelasting waarbij het eerste argument een string is die de weergavenaam van de assembly aangeeft die moet worden geladen (oftewel de string die door de Assembly.FullName eigenschap wordt geretourneerd).
Een AppDomain.Load overbelasting van de methode of Assembly.Load overbelasting van de methode waarvan het eerste argument een AssemblyName object is dat de assembly identificeert die moet worden geladen.
Een Assembly.LoadWithPartialName overbelasting van een methode.
Een AppDomain.CreateInstance overbelasting van een of AppDomain.CreateInstanceAndUnwrap methode waarmee een object in een ander toepassingsdomein wordt geïnstitueert.
Wat de event handler doet
De handler voor de AssemblyResolve gebeurtenis ontvangt in de ResolveEventArgs.Name eigenschap de weergavenaam van de assembly die moet worden geladen. Als de handler de assemblynaam niet herkent, wordt deze geretourneerd null (C#), Nothing (Visual Basic) of nullptr (Visual C++).
Als de handler de assemblynaam herkent, kan deze een assembly laden en retourneren die voldoet aan de aanvraag. In de volgende lijst worden enkele voorbeeldscenario's beschreven.
Als de handler de locatie van een versie van de assembly kent, kan de assembly worden geladen met behulp van de Assembly.LoadFrom of Assembly.LoadFile methode en kan de geladen assembly worden geretourneerd als dit lukt.
Als de handler toegang heeft tot een database met assembly's die zijn opgeslagen als byte-arrays, kan deze een byte-array laden met behulp van een van de Assembly.Load methode-overbelastingen die een byte-array als parameter accepteren.
De handler kan een dynamische assembly genereren en deze retourneren.
Opmerking
De handler moet de assembly laden in de load-from-context, in de load-context of zonder context. Als de handler de assembly met behulp van Assembly.ReflectionOnlyLoad of Assembly.ReflectionOnlyLoadFrom methode in de alleen-reflectiecontext laadt, mislukt de laadpoging die de AssemblyResolve gebeurtenis heeft veroorzaakt.
Het is de verantwoordelijkheid van de gebeurtenishandler om een geschikte assembly te retourneren. De handler kan de weergavenaam van de aangevraagde assembly parseren door de ResolveEventArgs.Name eigenschapswaarde door te geven aan de AssemblyName(String) constructor. Vanaf .NET Framework 4 kan de handler de ResolveEventArgs.RequestingAssembly eigenschap gebruiken om te bepalen of de huidige aanvraag afhankelijk is van een andere assembly. Deze informatie kan helpen bij het identificeren van een assembly die voldoet aan de afhankelijkheid.
De gebeurtenis-handler kan een andere versie van de assembly retourneren dan de versie die is aangevraagd.
In de meeste gevallen wordt de assembly die wordt geretourneerd door de handler weergegeven in de laadcontext, ongeacht de context waarin de handler deze laadt. Als de handler bijvoorbeeld de Assembly.LoadFrom methode gebruikt om een assembly in de load-from context te laden, wordt de assembly weergegeven in de load context wanneer de handler deze retourneert. In het volgende geval wordt de assembly echter zonder context weergegeven wanneer de handler deze retourneert:
De handler laadt een assembly zonder context.
De ResolveEventArgs.RequestingAssembly eigenschap is niet null.
De gevraagde assembly (dat wil zeggen, de assembly die door de ResolveEventArgs.RequestingAssembly eigenschap wordt geretourneerd) werd zonder context geladen.
Zie de overbelasting van de Assembly.LoadFrom(String) methode voor meer informatie over contexten.
Meerdere versies van dezelfde assembly kunnen in hetzelfde toepassingsdomein worden geladen. Deze procedure wordt niet aanbevolen, omdat dit kan leiden tot typetoewijzingsproblemen. Zie Beste praktijken voor het laden van assembly's.
Wat de eventhandler niet mag doen
De primaire regel voor het afhandelen van de AssemblyResolve gebeurtenis is dat u niet moet proberen een assembly te retourneren die u niet herkent. Wanneer u de handler schrijft, moet u weten welke assembly's de gebeurtenis kunnen oproepen. Uw handler moet null retourneren voor andere assembly's.
Belangrijk
Vanaf .NET Framework 4 wordt het AssemblyResolve-event gegenereerd voor satellietassemblies. Deze wijziging is van invloed op een gebeurtenishandler die is geschreven voor een eerdere versie van .NET Framework, als de handler alle assembly-laadverzoeken probeert af te handelen. Gebeurtenis-handlers die assemblies negeren die ze niet herkennen, worden niet beïnvloed door deze wijziging: ze retourneren null en normale terugvalmechanismen worden gevolgd.
Bij het laden van een assembly mag de event-handler geen van de AppDomain.Load of Assembly.Load method-overloads gebruiken die ervoor kunnen zorgen dat de AssemblyResolve gebeurtenis recursief wordt gegenereerd, omdat dit kan leiden tot een stack overflow. (Zie de lijst die eerder in dit onderwerp is opgegeven.) Dit gebeurt zelfs als u uitzonderingsafhandeling voor de laadaanvraag opgeeft, omdat er geen uitzondering wordt gegenereerd totdat alle event handlers zijn uitgevoerd. De volgende code resulteert in een stack-overloop als MyAssembly niet wordt gevonden:
using System;
using System.Reflection;
class BadExample
{
static void Main()
{
AppDomain ad = AppDomain.CreateDomain("Test");
ad.AssemblyResolve += MyHandler;
try
{
object obj = ad.CreateInstanceAndUnwrap(
"MyAssembly, version=1.2.3.4, culture=neutral, publicKeyToken=null",
"MyType");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
static Assembly MyHandler(object source, ResolveEventArgs e)
{
Console.WriteLine("Resolving {0}", e.Name);
// DO NOT DO THIS: This causes a StackOverflowException
return Assembly.Load(e.Name);
}
}
/* This example produces output similar to the following:
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
...
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
Process is terminated due to StackOverflowException.
*/
Imports System.Reflection
Class BadExample
Shared Sub Main()
Dim ad As AppDomain = AppDomain.CreateDomain("Test")
AddHandler ad.AssemblyResolve, AddressOf MyHandler
Try
Dim obj As object = ad.CreateInstanceAndUnwrap(
"MyAssembly, version=1.2.3.4, culture=neutral, publicKeyToken=null",
"MyType")
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
End Sub
Shared Function MyHandler(ByVal source As Object, _
ByVal e As ResolveEventArgs) As Assembly
Console.WriteLine("Resolving {0}", e.Name)
// DO NOT DO THIS: This causes a StackOverflowException
Return Assembly.Load(e.Name)
End Function
End Class
' This example produces output similar to the following:
'
'Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
'Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
'...
'Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
'Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
'
'Process is terminated due to StackOverflowException.
using namespace System;
using namespace System::Reflection;
ref class Example
{
internal:
static Assembly^ MyHandler(Object^ source, ResolveEventArgs^ e)
{
Console::WriteLine("Resolving {0}", e->Name);
// DO NOT DO THIS: This causes a StackOverflowException
return Assembly::Load(e->Name);
}
};
void main()
{
AppDomain^ ad = AppDomain::CreateDomain("Test");
ad->AssemblyResolve += gcnew ResolveEventHandler(&Example::MyHandler);
try
{
Object^ obj = ad->CreateInstanceAndUnwrap(
"MyAssembly, version=1.2.3.4, culture=neutral, publicKeyToken=null",
"MyType");
}
catch (Exception^ ex)
{
Console::WriteLine(ex->Message);
}
}
/* This example produces output similar to the following:
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
...
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
Process is terminated due to StackOverflowException.
*/
De juiste manier om AssemblyResolve te verwerken
Bij het oplossen van assemblies vanuit de AssemblyResolve gebeurtenishandler zal er uiteindelijk een StackOverflowException optreden als de handler gebruikmaakt van de Assembly.Load- of AppDomain.Load-aanroepmethodes. In plaats daarvan, gebruik LoadFile of LoadFrom methoden, omdat ze de AssemblyResolve gebeurtenis niet genereren.
Stel dat MyAssembly.dll zich in de buurt van de uitvoerassembly bevindt, op een bekende locatie, zodat het kan worden opgelost met behulp van Assembly.LoadFile en het pad naar de assembly.
using System;
using System.IO;
using System.Reflection;
class CorrectExample
{
static void Main()
{
AppDomain ad = AppDomain.CreateDomain("Test");
ad.AssemblyResolve += MyHandler;
try
{
object obj = ad.CreateInstanceAndUnwrap(
"MyAssembly, version=1.2.3.4, culture=neutral, publicKeyToken=null",
"MyType");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
static Assembly MyHandler(object source, ResolveEventArgs e)
{
Console.WriteLine("Resolving {0}", e.Name);
var path = Path.GetFullPath("../../MyAssembly.dll");
return Assembly.LoadFile(path);
}
}
Imports System.IO
Imports System.Reflection
Class CorrectExample
Shared Sub Main()
Dim ad As AppDomain = AppDomain.CreateDomain("Test")
AddHandler ad.AssemblyResolve, AddressOf MyHandler
Try
Dim obj As Object = ad.CreateInstanceAndUnwrap(
"MyAssembly, version=1.2.3.4, culture=neutral, publicKeyToken=null",
"MyType")
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
End Sub
Shared Function MyHandler(ByVal source As Object,
ByVal e As ResolveEventArgs) As Assembly
Console.WriteLine("Resolving {0}", e.Name)
Dim fullPath = Path.GetFullPath("../../MyAssembly.dll")
Return Assembly.LoadFile(fullPath)
End Function
End Class
using namespace System;
using namespace System::IO;
using namespace System::Reflection;
ref class Example
{
internal:
static Assembly^ MyHandler(Object^ source, ResolveEventArgs^ e)
{
Console::WriteLine("Resolving {0}", e->Name);
String^ fullPath = Path::GetFullPath("../../MyAssembly.dll");
return Assembly::LoadFile(fullPath);
}
};
void main()
{
AppDomain^ ad = AppDomain::CreateDomain("Test");
ad->AssemblyResolve += gcnew ResolveEventHandler(&Example::MyHandler);
try
{
Object^ obj = ad->CreateInstanceAndUnwrap(
"MyAssembly, version=1.2.3.4, culture=neutral, publicKeyToken=null",
"MyType");
}
catch (Exception^ ex)
{
Console::WriteLine(ex->Message);
}
}