Resolver cargas de ensamblado

.NET Framework proporciona el evento AppDomain.AssemblyResolve para las aplicaciones que necesitan un mayor control sobre la carga de ensamblados. Controlando este evento, la aplicación puede cargar un ensamblado en el contexto de carga desde fuera de las rutas de acceso de sondeo normales, seleccionar cuál de las diversas versiones del ensamblado se va a cargar, emitir un ensamblado dinámico y devolverlo, etc. En este tema se proporcionan directrices para controlar el evento AssemblyResolve.

NotaNota

Para resolver las cargas de ensamblados en el contexto de solo reflexión, use el evento AppDomain.ReflectionOnlyAssemblyResolve en su lugar.

Cómo funciona el evento AssemblyResolve

Cuando se registra un controlador para el evento AssemblyResolve, se invoca el controlador siempre que el runtime no puede enlazarse a un ensamblado por nombre. Por ejemplo, la llamada a los métodos siguientes desde código de usuario puede hacer que se genere el evento AssemblyResolve:

Qué hace el controlador de eventos

El controlador para el evento AssemblyResolve recibe el nombre para mostrar del ensamblado que se va a cargar, en la propiedad ResolveEventArgs.Name. Si el controlador no reconoce el nombre de ensamblado, devuelve NULL (Nothing en Visual Basic, nullptr en Visual C++).

Si el controlador reconoce el nombre de ensamblado, puede cargar y devolver un ensamblado que satisfaga la solicitud. En la lista siguiente se describen algunos escenarios de ejemplo.

  • Si el controlador conoce la ubicación de una versión del ensamblado, puede cargar el ensamblado usando el método Assembly.LoadFrom o Assembly.LoadFile, y puede devolver el ensamblado cargado si se ejecuta correctamente.

  • Si el controlador tiene acceso a una base de datos de ensamblados almacenados como matrices de bytes, puede cargar una matriz de bytes mediante una de las sobrecargas del método Assembly.Load que toma una matriz de bytes.

  • El controlador puede generar un ensamblado dinámico y devolverlo.

NotaNota

El controlador debe cargar el ensamblado en el contexto de origen de carga, en el contexto de carga o sin contexto.Si el controlador carga el ensamblado en el contexto de solo reflexión mediante el método Assembly.ReflectionOnlyLoad o Assembly.ReflectionOnlyLoadFrom, el intento de carga que generó el evento AssemblyResolve producirá un error.

Es responsabilidad del controlador de eventos devolver un ensamblado apropiado. El controlador puede analizar el nombre para mostrar del ensamblado solicitado pasando el valor de propiedad ResolveEventArgs.Name al constructor AssemblyName(String). A partir de .NET Framework versión 4, el controlador puede usar la propiedad ResolveEventArgs.RequestingAssembly para determinar si la solicitud actual es una dependencia de otro ensamblado. Esta información puede ayudar a identificar un ensamblado que satisface la dependencia.

El controlador de eventos puede devolver una versión diferente del ensamblado que la versión solicitada.

En la mayoría de los casos, el ensamblado devuelto por el controlador aparece en el contexto de carga, independientemente del contexto en el que el controlador lo carga. Por ejemplo, si el controlador usa el método Assembly.LoadFrom para cargar un ensamblado en el contexto de origen de carga, el ensamblado aparece en el contexto de carga cuando el controlador lo devuelve. Sin embargo, en el caso siguiente el ensamblado aparece sin contexto cuando el controlador lo devuelve:

Para obtener información sobre los contextos, vea la sobrecarga del método Assembly.LoadFrom(String).

Se pueden cargar varias versiones del mismo ensamblado en el mismo dominio de aplicación. Este procedimiento no se recomienda, porque puede conducir a problemas de asignación de tipos. Vea Procedimientos recomendados para cargar ensamblados.

Lo que el controlador de eventos no debe hacer

La regla principal para controlar el evento AssemblyResolve es que no debe intentar devolver un ensamblado que no se reconoce. Cuando se escribe el controlador, debe saber qué ensamblados pueden generar el evento. El controlador debe devolver NULL para otros ensamblados.

Nota importanteImportante

A partir de .NET Framework 4, el evento AssemblyResolve se genera para los ensamblados satélites.Este cambio afecta a un controlador de eventos escrito para una versión anterior de .NET Framework, si el controlador intenta resolver todas las solicitudes de carga de ensamblados.Los controladores de eventos que omiten los ensamblados no reconocen que no se ven afectados por este cambio: devuelven NULL y se siguen los mecanismos normales de reserva.

Al cargar un ensamblado, el controlador de eventos no debe usar ninguna de las sobrecargas del método AppDomain.Load o Assembly.Load que pueden hacer que el evento AssemblyResolve se genere de forma recursiva, porque puede dar lugar a un desbordamiento de pila. (Vea la lista proporcionada anteriormente en este tema.) Esto ocurre incluso si proporciona el control de excepciones para la solicitud de carga, ya que no se produce ninguna excepción hasta que todos los controladores de eventos hayan vuelto. Por tanto, el código siguiente produce un desbordamiento de la pila si MyAssembly no se encuentra:

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

Vea también

Otros recursos

Procedimientos recomendados para cargar ensamblados

Utilizar dominios de aplicación