Auflösen beim Laden von AssemblysResolving Assembly Loads

.NET Framework stellt das Ereignis AppDomain.AssemblyResolve für Anwendungen bereit, die eine erhöhte Steuerung des Ladens von Assemblys erfordern.The .NET Framework provides the AppDomain.AssemblyResolve event for applications that require greater control over assembly loading. Durch das Behandeln dieses Ereignisses kann Ihre Anwendung eine Assembly außerhalb der Prüfpfade in einen Kontext laden, vor dem Laden zwischen verschiedenen Assemblyversionen wählen, eine dynamische Assembly ausgeben und diese zurückgeben und so weiter.By handling this event, your application can load an assembly into the load context from outside the normal probing paths, select which of several assembly versions to load, emit a dynamic assembly and return it, and so on. In diesem Thema erhalten Sie eine Anleitung zum Behandeln des Ereignisses AssemblyResolve.This topic provides guidance for handling the AssemblyResolve event.

Hinweis

Zum Auflösen vom Laden einer Assembly in einem reflektionsbezogenen Kontext können Sie stattdessen das Ereignis AppDomain.ReflectionOnlyAssemblyResolve verwenden.For resolving assembly loads in the reflection-only context, use the AppDomain.ReflectionOnlyAssemblyResolve event instead.

Arbeitsweise des Ereignisses „AssemblyResolve“How the AssemblyResolve Event Works

Wenn Sie einen Handler für das Ereignis AssemblyResolve registrieren, wird der Handler immer dann aufgerufen, wenn die Runtime eine Assembly nicht anhand deren Namen binden kann.When you register a handler for the AssemblyResolve event, the handler is invoked whenever the runtime fails to bind to an assembly by name. Wenn Sie z.B. die folgende Methode aus Benutzercode aufrufen, kann das Ereignis AssemblyResolve ausgelöst werden:For example, calling the following methods from user code can cause the AssemblyResolve event to be raised:

Was der Ereignishandler machtWhat the Event Handler Does

Der Handler für das Ereignis AssemblyResolve erhält den Anzeigenamen der zu ladenden Assembly in der Eigenschaft ResolveEventArgs.Name.The handler for the AssemblyResolve event receives the display name of the assembly to be loaded, in the ResolveEventArgs.Name property. Wenn der Handler den Assemblynamen nicht erkennt, gibt er NULL zurück (Nothing in Visual Basic, nullptr in Visual C++).If the handler does not recognize the assembly name, it returns null (Nothing in Visual Basic, nullptr in Visual C++).

Wenn der Handler den Assemblynamen erkennt, kann er eine Assembly laden und zurückgeben, die der Anforderung entspricht.If the handler recognizes the assembly name, it can load and return an assembly that satisfies the request. In der folgenden Liste werden einige Beispielszenarios beschrieben.The following list describes some sample scenarios.

  • Wenn der Handler den Speicherort einer Version der Assembly kennt, kann er die Assembly mit den Methoden Assembly.LoadFrom oder Assembly.LoadFile laden und bei Erfolg die geladene Assembly zurückgeben.If the handler knows the location of a version of the assembly, it can load the assembly by using the Assembly.LoadFrom or Assembly.LoadFile method, and can return the loaded assembly if successful.

  • Wenn der Handler auf die Datenbank von Assemblys zugreifen kann, die als Bytearrays gespeichert sind, kann er das Bytearray mit den Methodenüberladungen Assembly.Load laden, die Bytearrays akzeptieren.If the handler has access to a database of assemblies stored as byte arrays, it can load a byte array by using one of the Assembly.Load method overloads that take a byte array.

  • Der Handler kann eine dynamische Assembly generieren und diese zurückgeben.The handler can generate a dynamic assembly and return it.

Hinweis

Der Handler muss die Assembly entweder in den load-from-Kontext, den load-Kontext oder ohne Kontext laden. Wenn der Handler die Assembly mit den Methoden Assembly.ReflectionOnlyLoad oder Assembly.ReflectionOnlyLoadFrom in den reflektionsbezogenen Kontext lädt, schlägt der Ladeversuch, der das Ereignis AssemblyResolve ausgelöst hat, fehl.The handler must load the assembly into the load-from context, into the load context, or without context.If the handler loads the assembly into the reflection-only context by using the Assembly.ReflectionOnlyLoad or the Assembly.ReflectionOnlyLoadFrom method, the load attempt that raised the AssemblyResolve event fails.

Der Ereignishandler ist dafür verantwortlich, eine passende Assembly zurückzugeben.It is the responsibility of the event handler to return a suitable assembly. Der Handler kann den Anzeigename der angeforderten Assembly analysieren, indem er den Wert der ResolveEventArgs.Name-Eigenschaft an den AssemblyName(String)-Konstruktor übergibt.The handler can parse the display name of the requested assembly by passing the ResolveEventArgs.Name property value to the AssemblyName(String) constructor. Ab .NET Framework 4 kann der Handler die ResolveEventArgs.RequestingAssembly-Eigenschaft verwenden, um zu bestimmen, ob die aktuelle Anforderung eine Abhängigkeit von einer anderen Assembly darstellt.Beginning with the .NET Framework 4, the handler can use the ResolveEventArgs.RequestingAssembly property to determine whether the current request is a dependency of another assembly. Diese Information kann dabei helfen, eine Assembly zu identifizieren die die Abhängigkeit erfüllt.This information can help identify an assembly that will satisfy the dependency.

Der Ereignishandler kann eine Version der Assembly zurückgeben, die sich von der angeforderten Version unterscheidet.The event handler can return a different version of the assembly than the version that was requested.

In den meisten Fällen befindet sich die vom Handler zurückgegebene Assembly in einem load-Kontext, unabhängig vom Kontext, in der der Handler sie lädt.In most cases, the assembly that is returned by the handler appears in the load context, regardless of the context the handler loads it into. Wenn der Handler z.B. die Assembly.LoadFrom-Methode verwendet, um eine Assembly in einen load-from-Kontext zu laden, befindet sich die Assembly im load-Kontext, wenn der Handler sie zurückgibt.For example, if the handler uses the Assembly.LoadFrom method to load an assembly into the load-from context, the assembly appears in the load context when the handler returns it. Im folgenden Kontext befindet sich die Assembly jedoch in keinem Kontext, wenn sie vom Handler zurückgegeben wird:However, in the following case the assembly appears without context when the handler returns it:

Weitere Informationen zu Kontexten finden Sie in der Methodenüberladung Assembly.LoadFrom(String).For information about contexts, see the Assembly.LoadFrom(String) method overload.

Mehrere Versionen derselben Assembly können in die gleiche Anwendungsdomäne geladen werden.Multiple versions of the same assembly can be loaded into the same application domain. Diese Vorgehensweise wird jedoch nicht empfohlen, da sie zu Problemen bei der Typzuweisung führen kann.This practice is not recommended, because it can lead to type assignment problems. Weitere Informationen finden Sie unter Best Practices for Assembly Loading (Bewährte Methoden für das Laden von Assemblys).See Best Practices for Assembly Loading.

Was der Ereignishandler nicht machen sollteWhat the Event Handler Should Not Do

Die erste Regeln beim Behandeln des Ereignis AssemblyResolve ist, dass Sie nie versuchen sollten, eine Assembly zurückzugeben, die Sie nicht erkennen.The primary rule for handling the AssemblyResolve event is that you should not try to return an assembly you do not recognize. Wenn Sie den Handler schreiben, sollten Sie wissen, welche Assemblys das Ereignis auslösen können.When you write the handler, you should know which assemblies might cause the event to be raised. Ihr Handler sollte für andere Assemblys NULL zurückgeben.Your handler should return null for other assemblies.

Wichtig

Ab .NET Framework 4 wird das Ereignis AssemblyResolve für Satellitenassemblys ausgelöst.Beginning with the .NET Framework 4, the AssemblyResolve event is raised for satellite assemblies. Diese Änderung betrifft Ereignishandler, die für eine frühere Version von .NET Framework geschrieben wurden, wenn diese versuchen, alle Ladeanforderungen von Assemblys aufzulösen.This change affects an event handler that was written for an earlier version of the .NET Framework, if the handler tries to resolve all assembly load requests. Ereignishandler, die nicht erkannte Assemblys ignorieren, sind von dieser Änderung nicht betroffen: Sie geben NULL zurück. Danach wird auf die üblichen Fallbackmechanismen zurückgegriffen.Event handlers that ignore assemblies they do not recognize are not affected by this change: They return null, and normal fallback mechanisms are followed.

Beim Laden einer Assembly darf der Ereignishandler nicht die Methodenüberladungen AppDomain.Load oder Assembly.Load verwendet, die dazu führen können, dass das Ereignis AssemblyResolve rekursiv ausgelöst wird, da dies zu einem Stapelüberlauf führen kann.When loading an assembly, the event handler must not use any of the AppDomain.Load or Assembly.Load method overloads that can cause the AssemblyResolve event to be raised recursively, because this can lead to a stack overflow. (Weitere Informationen finden Sie in der weiter oben in diesem Thema angegebenen Liste.) Dies geschieht auch, wenn Sie eine Ausnahmebehandlung für die Ladeanforderung bereitstellen, da keine Ausnahme ausgelöst wird, bis alle Ereignishandler etwas zurückgegeben haben.(See the list provided earlier in this topic.) This happens even if you provide exception handling for the load request, because no exception is thrown until all event handlers have returned. Deshalb führt der folgende Code zu einem Stapelüberlauf, wenn MyAssembly nicht gefunden werden kann:Thus, the following code results in a stack overflow if MyAssembly is not found:

using namespace System;
using namespace System::Reflection;

ref class Example
{
internal:
    static Assembly^ MyHandler(Object^ source, ResolveEventArgs^ e) 
    {
        Console::WriteLine("Resolving {0}", e->Name);
        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.
 */
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);
        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
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)
        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.

Siehe auchSee also