Freigeben über


Auflösen beim Laden von Assemblys

.NET Framework stellt das AppDomain.AssemblyResolve-Ereignis für Anwendungen bereit, die umfassendere Steuerungsmöglichkeiten beim Laden von Assemblys erfordern. Durch Behandlung dieses Ereignisses kann Ihre Anwendung eine Assembly von Speicherorten außerhalb der normalen Prüfpfade in den Load-Kontext laden, die zu ladenden Assemblyversionen auswählen, eine dynamische Assembly ausgeben und zurückgeben usw. Dieses Thema enthält Anleitungen für die Behandlung des AssemblyResolve-Ereignisses.

HinweisHinweis

Um das Laden von Assemblys im reflektionsbezogenen Kontext aufzulösen, verwenden Sie stattdessen das AppDomain.ReflectionOnlyAssemblyResolve-Ereignis.

So funktioniert das AssemblyResolve-Ereignis

Wenn Sie einen Handler für das AssemblyResolve-Ereignis registrieren, wird dieser Handler immer dann aufgerufen, wenn die Laufzeit eine Assembly nicht nach dem Namen binden kann. Das Aufrufen der folgenden Methoden im Benutzercode kann beispielsweise dazu führen, dass das AssemblyResolve-Ereignis ausgelöst wird:

So funktioniert der Ereignishandler

Der Handler für das AssemblyResolve-Ereignis empfängt den Anzeigenamen der zu ladenden Assembly in der ResolveEventArgs.Name-Eigenschaft. Wenn der Handler den Assemblynamen nicht erkennt, wird NULL zurückgegeben (Nothing in Visual Basic, nullptr in Visual C++).

Wenn der Handler den Assemblynamen erkennt, kann er eine Assembly laden und zurückgeben, die die Anforderung erfüllt. In der folgenden Liste werden einige Beispielszenarien beschrieben.

  • Wenn der Handler den Speicherort einer Version der Assembly kennt, kann er die Assembly unter Verwendung der Assembly.LoadFrom-Methode oder der Assembly.LoadFile-Methode laden und bei erfolgreicher Durchführung die geladene Assembly zurückgeben.

  • Wenn der Handler Zugriff auf eine Datenbank mit Assemblys hat, die als Bytearrays gespeichert sind, kann er ein Bytearray laden. Hierzu wird eine der Assembly.Load-Methodenüberladungen verwendet, die ein Bytearray annehmen.

  • Der Handler kann eine dynamische Assembly generieren und zurückgeben.

HinweisHinweis

Der Handler muss die Assembly in den LoadFrom-Kontext, in den Ladekontext oder ohne Kontext laden.Wenn der Handler die Assembly unter Verwendung der Assembly.ReflectionOnlyLoad-Methode oder der Assembly.ReflectionOnlyLoadFrom-Methode in den reflektionsbezogenen Kontext lädt, schlägt der Ladeversuch, der das AssemblyResolve-Ereignis ausgelöst hat, fehl.

Es liegt in der Verantwortung des Ereignishandlers, eine geeignete Assembly zurückzugeben. Der Handler kann den Anzeigenamen der angeforderten Assembly analysieren, indem er den ResolveEventArgs.Name-Eigenschaftswert an den AssemblyName(String)-Konstruktor übergibt. Ab .NET Framework, Version 4 kann der Handler die ResolveEventArgs.RequestingAssembly-Eigenschaft verwenden, um zu bestimmen, ob die aktuelle Anforderung eine Abhängigkeit einer anderen Assembly darstellt. Diese Informationen können dabei helfen, eine Assembly zu identifizieren, die die Abhängigkeit erfüllt.

Der Ereignishandler kann eine andere Version als die angeforderte Version der Assembly zurückgeben.

In den meisten Fällen wird die vom Handler zurückgegebene Assembly im Ladekontext enthalten sein, unabhängig vom Kontext, in den der Handler lädt. Wenn der Handler zum Beispiel die Assembly.LoadFrom-Methode verwendet, um eine Assembly in den LoadFrom-Kontext zu laden, ist die Assembly im Ladekontext enthalten, wenn sie vom Handler zurückgegeben wird. Im folgenden Fall erscheint die Assembly jedoch ohne Kontext, wenn sie vom Handler zurückgegeben wird:

Weitere Informationen zu Kontexten finden Sie unter der Assembly.LoadFrom(String) Methodenüberladung.

Mehrere Versionen einer Assembly können in dieselbe Anwendungsdomäne geladen werden. Diese Vorgehensweise wird nicht empfohlen, da sie zu Problemen bei der Zuweisung führen kann. Siehe Best Practices für das Laden von Assemblys.

Nicht empfohlene Verwendung des Ereignishandlers

Die Hauptregel für die Behandlung des AssemblyResolve-Ereignisses besteht darin, nicht zu versuchen, eine nicht erkannte Assembly zurückzugeben. Wenn Sie den Handler erstellen, sollten Sie wissen, welche Assemblys möglicherweise das Ereignis auslösen. Der Handler sollte für andere Assemblys NULL zurückgeben.

Wichtiger HinweisWichtig

Ab .NET Framework 4 wird das AssemblyResolve-Ereignis für Satellitenassemblys ausgelöst.Diese Änderung betrifft einen Ereignishandler, der für eine frühere Version von .NET Framework geschrieben wurde, wenn der Handler versucht, alle Anforderungen für das Laden von Assemblys aufzulösen.Ereignishandler, die nicht erkannte Assemblys ignorieren, sind von dieser Änderung nicht betroffen: Sie geben NULL zurück, und normale Fallbackmechanismen werden befolgt.

Beim Laden einer Assembly darf der Ereignishandler keine der AppDomain.Load-Methodenüberladungen oder der Assembly.Load-Methodenüberladungen verwenden, die das rekursive Auslösen des AssemblyResolve-Ereignisses verursachen können, da dies zu einem Stapelüberlauf führen kann. (Weitere Informationen finden Sie in der Liste weiter oben in diesem Thema.) Dies tritt auch dann ein, wenn Sie eine Ausnahmebehandlung für die Ladeanforderung bereitstellen, da keine Ausnahme ausgelöst wird, bis alle Ereignishandler zurückgegeben wurden. Somit führt der folgende Code zu einem Stapelüberlauf, wenn MyAssembly nicht gefunden wird:

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.
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.
 */
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.
 */

Siehe auch

Weitere Ressourcen

Best Practices für das Laden von Assemblys

Verwenden von Anwendungsdomänen