Eventos
Cree aplicaciones inteligentes
17 mar, 9 p.m. - 21 mar, 10 a.m.
Únete a la serie de encuentros para crear soluciones de IA escalables basadas en casos de uso del mundo real con otros desarrolladores y expertos.
Regístrese ahoraEste explorador ya no es compatible.
Actualice a Microsoft Edge para aprovechar las características, las actualizaciones de seguridad y el soporte técnico más recientes.
.NET proporciona el evento AppDomain.AssemblyResolve para aplicaciones que requieren un mayor control sobre la carga de ensamblados. Al controlar 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 qué versión de ensamblado cargar, emitir un ensamblado dinámico y devolverlo, etc. En este tema se proporcionan instrucciones para controlar el evento AssemblyResolve.
Nota
Para resolver cargas de ensamblado en el contexto de solo reflexión, use en su lugar el evento AppDomain.ReflectionOnlyAssemblyResolve.
Al registrar un controlador para el evento AssemblyResolve, se invoca el controlador si se produce un error cuando el tiempo de ejecución enlaza a un ensamblado por nombre. Por ejemplo, si se llama a los métodos siguientes desde el código de usuario, puede producirse el evento AssemblyResolve:
Una sobrecarga del método AppDomain.Load o una sobrecarga del método Assembly.Load cuyo primer argumento es una cadena que representa el nombre para mostrar del ensamblado que se va a cargar (es decir, la cadena devuelta por la propiedad Assembly.FullName).
Una sobrecarga del método AppDomain.Load o una sobrecarga del método Assembly.Load cuyo primer argumento es un objeto AssemblyName que identifica el ensamblado que se va a cargar.
Una sobrecarga del método Assembly.LoadWithPartialName.
Una sobrecarga del método AppDomain.CreateInstance o AppDomain.CreateInstanceAndUnwrap que crea instancias de un objeto en otro dominio de aplicación.
El controlador del 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 del ensamblado, devuelve null
(C#), Nothing
(Visual Basic) o nullptr
(Visual C++).
Si el controlador reconoce el nombre del ensamblado, puede cargar y devolver un ensamblado que cumpla 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 mediante el método Assembly.LoadFrom o Assembly.LoadFile y devolver el ensamblado cargado si se realiza correctamente.
Si el controlador tiene acceso a una base de datos de los ensamblados almacenados como matrices de bytes, puede cargar una matriz de bytes mediante una de las sobrecargas del método Assembly.Load que toman una matriz de bytes.
El controlador puede generar un ensamblado dinámico y devolverlo.
Nota
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 Assembly.ReflectionOnlyLoad o el método Assembly.ReflectionOnlyLoadFrom, el intento de carga que ha generado el evento AssemblyResolve sufre un error.
El controlador de eventos se encarga de devolver un ensamblado adecuado. El controlador puede analizar el nombre para mostrar del ensamblado solicitado. Para ello, pasa el valor de propiedad ResolveEventArgs.Name al constructor AssemblyName(String). A partir de .NET Framework 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 cumplirá la dependencia.
El controlador de eventos puede devolver una versión del ensamblado diferente de la versión solicitada.
En la mayoría de los casos, el ensamblado que el controlador devuelve aparece en el contexto de carga, independientemente del contexto en el que lo carga el controlador. 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. Pero en el caso siguiente, el ensamblado aparece sin contexto cuando el controlador lo devuelve:
El controlador carga un ensamblado sin contexto.
La propiedad ResolveEventArgs.RequestingAssembly no es NULL.
El ensamblado solicitante (es decir, el ensamblado devuelto por la propiedad ResolveEventArgs.RequestingAssembly) se ha cargado sin contexto.
Para obtener información sobre los contextos, vea la sobrecarga del método Assembly.LoadFrom(String).
Es posible cargar varias versiones del mismo ensamblado en el mismo dominio de aplicación, pero esta práctica no se recomienda porque puede provocar problemas de asignación de tipos. Vea Procedimientos recomendados para cargar ensamblados.
La regla principal que debe observar para controlar el evento AssemblyResolve es que no debe intentar devolver un ensamblado que no reconozca. Cuando se escribe el controlador, debe saber qué ensamblados pueden hacer que se produzca el evento. El controlador debe devolver NULL para otros ensamblados.
Importante
A partir de .NET Framework 4, se genera el evento AssemblyResolve para los ensamblados satélite. Este cambio afecta a los controladores de eventos escritos para versiones anteriores de .NET Framework si intentan resolver todas las solicitudes de carga del ensamblado. Este cambio no afecta a los controladores de eventos que omiten los ensamblados que no reconocen: devuelven null
y se siguen los mecanismos normales de reserva.
Al cargar un ensamblado, el controlador de eventos no debe usar las sobrecargas del método AppDomain.Load o Assembly.Load que pueden hacer que se produzca el evento AssemblyResolve de forma recursiva, ya que esto puede provocar 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, porque no se produce ninguna excepción hasta que se hayan devuelto todos los controladores de eventos. Así pues, el código siguiente produce un desbordamiento de pila si no se encuentra MyAssembly
:
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.
*/
Al resolver ensamblados desde el controlador de eventos AssemblyResolve, al final se inicia una excepción StackOverflowException si el controlador usa las llamadas al método Assembly.Load o AppDomain.Load. En su lugar, use métodos LoadFile o LoadFrom, ya que no generan el evento AssemblyResolve
.
Imagine que MyAssembly.dll
se encuentra cerca del ensamblado en ejecución, en una ubicación conocida, se puede resolver mediante Assembly.LoadFile
dada la ruta de acceso al ensamblado.
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);
}
}
Comentarios de .NET
.NET es un proyecto de código abierto. Selecciona un vínculo para proporcionar comentarios:
Eventos
Cree aplicaciones inteligentes
17 mar, 9 p.m. - 21 mar, 10 a.m.
Únete a la serie de encuentros para crear soluciones de IA escalables basadas en casos de uso del mundo real con otros desarrolladores y expertos.
Regístrese ahoraFormación
Módulo
Implementación del control de excepciones en aplicaciones de consola de C# - Training
En este módulo se explora el uso de excepciones y el proceso de control de excepciones en aplicaciones de consola de C#. Las actividades prácticas proporcionan experiencia en la implementación de patrones de control de excepciones para varios escenarios de codificación.
Documentación
Procedimientos recomendados para cargar ensamblados - .NET Framework
Explore los procedimientos recomendados para cargar ensamblados en .NET. Evite problemas de identidad de tipos que pueden conducir a conversiones no válidas, métodos que faltan y otras excepciones.
Cómo el motor en tiempo de ejecución ubica ensamblados - .NET Framework
Aprenda como Common Language Runtime (CLR) localiza los ensamblados que conforman la aplicación en .NET y se enlaza con ellos.
<probing> (Elemento) - .NET Framework
Más información sobre el elemento
Especificar la ubicación de un ensamblado - .NET Framework
Vea cómo especificar la ubicación de un ensamblado en .NET mediante el elemento codeBase o el elemento de sondeo en un archivo de configuración XML.