Rozwiązywanie załadowań zestawówResolve assembly loads

Platforma .NET udostępnia zdarzenie AppDomain.AssemblyResolve dla aplikacji, które wymagają większej kontroli nad ładowaniem zestawu..NET provides the AppDomain.AssemblyResolve event for applications that require greater control over assembly loading. Dzięki obsłudze tego zdarzenia aplikacja może załadować zestaw do kontekstu obciążenia spoza normalnej ścieżki sondowania, wybrać kilka wersji zestawu do załadowania, emitować zestaw dynamiczny i zwrócić go i tak dalej.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. Ten temat zawiera wskazówki dotyczące obsługi zdarzenia AssemblyResolve.This topic provides guidance for handling the AssemblyResolve event.

Uwaga

W celu rozpoznawania obciążeń zestawów w kontekście tylko odbicia należy zamiast tego użyć zdarzenia AppDomain.ReflectionOnlyAssemblyResolve.For resolving assembly loads in the reflection-only context, use the AppDomain.ReflectionOnlyAssemblyResolve event instead.

Jak działa zdarzenie AssemblyResolveHow the AssemblyResolve event works

Po zarejestrowaniu procedury obsługi dla zdarzenia AssemblyResolve, procedura obsługi jest wywoływana za każdym razem, gdy środowisko uruchomieniowe nie uda się powiązać z zestawem według nazwy.When you register a handler for the AssemblyResolve event, the handler is invoked whenever the runtime fails to bind to an assembly by name. Na przykład wywoływanie następujących metod z kodu użytkownika może spowodować podniesienie poziomu zdarzenia AssemblyResolve:For example, calling the following methods from user code can cause the AssemblyResolve event to be raised:

Działanie programu obsługi zdarzeńWhat the event handler does

Procedura obsługi dla zdarzenia AssemblyResolve otrzymuje nazwę wyświetlaną zestawu, który ma zostać załadowany, we właściwości ResolveEventArgs.Name.The handler for the AssemblyResolve event receives the display name of the assembly to be loaded, in the ResolveEventArgs.Name property. Jeśli program obsługi nie rozpoznaje nazwy zestawu, zwraca null (C#), Nothing (Visual Basic) lub nullptr (wizualizacja C++).If the handler does not recognize the assembly name, it returns null (C#), Nothing (Visual Basic), or nullptr (Visual C++).

Jeśli program obsługi rozpoznaje nazwę zestawu, może ładować i zwracać zestaw, który spełnia żądanie.If the handler recognizes the assembly name, it can load and return an assembly that satisfies the request. Na poniższej liście opisano kilka przykładowych scenariuszy.The following list describes some sample scenarios.

  • Jeśli program obsługi wie lokalizację wersji zestawu, może załadować zestaw za pomocą metody Assembly.LoadFrom lub Assembly.LoadFile i może zwrócić załadowany zestaw, jeśli zakończono pomyślnie.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.

  • Jeśli program obsługi ma dostęp do bazy danych zestawów przechowywanych jako tablice bajtowe, może załadować tablicę bajtową przy użyciu jednego z przeciążeń metody Assembly.Load, które pobierają tablicę bajtów.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.

  • Program obsługi może wygenerować zestaw dynamiczny i zwrócić go.The handler can generate a dynamic assembly and return it.

Uwaga

Program obsługi musi załadować zestaw do kontekstu ładowania z w kontekście ładowania lub bez kontekstu. Jeśli program obsługi ładuje zestaw do kontekstu tylko odbicie przy użyciu Assembly.ReflectionOnlyLoad lub metody Assembly.ReflectionOnlyLoadFrom, próba załadowania, która wywołała zdarzenie AssemblyResolve, kończy się niepowodzeniem.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.

Do zwrócenia odpowiedniego zestawu jest odpowiedzialna procedura obsługi zdarzeń.It is the responsibility of the event handler to return a suitable assembly. Program obsługi może przeanalizować nazwę wyświetlaną żądanego zestawu, przekazując wartość właściwości ResolveEventArgs.Name do konstruktora AssemblyName(String).The handler can parse the display name of the requested assembly by passing the ResolveEventArgs.Name property value to the AssemblyName(String) constructor. Począwszy od .NET Framework 4, program obsługi może użyć właściwości ResolveEventArgs.RequestingAssembly, aby określić, czy bieżące żądanie jest zależne od innego zestawu.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. Te informacje mogą ułatwić zidentyfikowanie zestawu, który będzie spełniał zależność.This information can help identify an assembly that will satisfy the dependency.

Program obsługi zdarzeń może zwrócić inną wersję zestawu niż żądana wersja.The event handler can return a different version of the assembly than the version that was requested.

W większości przypadków zestaw, który jest zwracany przez program obsługi, pojawia się w kontekście ładowania, niezależnie od kontekstu, w którym program obsługi ładuje go do.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. Jeśli na przykład program obsługi używa metody Assembly.LoadFrom do załadowania zestawu do kontekstu ładowania z, zestaw pojawia się w kontekście ładowania, gdy program obsługi zwróci go.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. Jednak w poniższym przypadku zestaw pojawia się bez kontekstu, gdy program obsługi zwróci go:However, in the following case the assembly appears without context when the handler returns it:

Aby uzyskać informacje na temat kontekstów, zobacz Przeciążenie metody Assembly.LoadFrom(String).For information about contexts, see the Assembly.LoadFrom(String) method overload.

Wiele wersji tego samego zestawu może być załadowanych do tej samej domeny aplikacji.Multiple versions of the same assembly can be loaded into the same application domain. Ta metoda nie jest zalecana, ponieważ może to prowadzić do problemów z przypisaniem.This practice is not recommended, because it can lead to type assignment problems. Zapoznaj się z najlepszymi rozwiązaniami dotyczącymi ładowania zestawu.See Best practices for assembly loading.

Czego nie powinien wykonać program obsługi zdarzeńWhat the event handler should not do

Podstawową regułą obsługi zdarzenia AssemblyResolve jest to, że nie należy próbować zwrócić zestawu, który nie jest rozpoznawany.The primary rule for handling the AssemblyResolve event is that you should not try to return an assembly you do not recognize. Podczas pisania procedury obsługi należy wiedzieć, które zestawy mogą spowodować podniesienie poziomu zdarzenia.When you write the handler, you should know which assemblies might cause the event to be raised. Program obsługi powinien zwrócić wartość null dla innych zestawów.Your handler should return null for other assemblies.

Ważne

Począwszy od .NET Framework 4, zdarzenie AssemblyResolve jest zgłaszane dla zestawów satelickich.Beginning with the .NET Framework 4, the AssemblyResolve event is raised for satellite assemblies. Ta zmiana ma wpływ na procedurę obsługi zdarzeń, która została zapisywana dla starszej wersji .NET Framework, jeśli program obsługi podejmie próbę rozpoznania wszystkich żądań ładowania zestawu.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. Procedury obsługi zdarzeń, które ignorują zestawy, które nie są rozpoznawane, nie mają wpływ na tę zmianę: zwracają wartości null i są stosowane normalne mechanizmy powrotu.Event handlers that ignore assemblies they do not recognize are not affected by this change: They return null, and normal fallback mechanisms are followed.

Podczas ładowania zestawu, procedura obsługi zdarzeń nie może używać żadnych przeciążeń metody AppDomain.Load lub Assembly.Load, które mogą spowodować rekursywne zdarzenie AssemblyResolve, ponieważ może to prowadzić do przepełnienia stosu.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. (Zobacz listę znajdującą się wcześniej w tym temacie). Dzieje się tak nawet wtedy, gdy podajesz obsługę wyjątków dla żądania ładowania, ponieważ żaden wyjątek nie jest zgłaszany do momentu zwrócenia wszystkich programów obsługi zdarzeń.(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. W rezultacie następujący kod powoduje przepełnienie stosu, jeśli nie można odnaleźć MyAssembly: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.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.

Zobacz takżeSee also