Risoluzione caricamenti assembly
.NET Framework fornisce l'evento AppDomain.AssemblyResolve per le applicazioni che richiedono un maggiore controllo sul caricamento dell'assembly. Gestendo questo evento, l'applicazione è in grado di caricare un assembly nel contesto di caricamento dall'esterno dei normali percorsi di sondaggio, selezionare la versione dell'assembly da caricare, creare un assembly dinamico e restituirlo e così via. In questo argomento vengono fornite le istruzioni per la gestione dell'evento AssemblyResolve.
![]() |
---|
Per risolvere i caricamenti degli assembly nel contesto solo reflection, utilizzare invece l'evento AppDomain.ReflectionOnlyAssemblyResolve. |
Funzionamento dell'evento AssemblyResolve
Quando si registra un gestore per l'evento AssemblyResolve, il gestore viene richiamato ogni volta che l'associazione di runtime a un assembly in base al nome avrà esito negativo. Ad esempio, la chiamata ai metodi seguenti dal codice utente può causare la generazione dell'evento AssemblyResolve:
Un overload del metodo AppDomain.Load o un overload del metodo Assembly.Load di cui il primo argomento è una stringa che rappresenta il nome visualizzato dell'assembly da caricare, ovvero la stringa restituita dalla proprietà Assembly.FullName.
Un overload del metodo AppDomain.Load o un overload del metodo Assembly.Load di cui il primo argomento è un oggetto AssemblyName che identifica l'assembly da caricare.
Un overload del metodo Assembly.LoadWithPartialName.
Un overload del metodo AppDomain.CreateInstanceAndUnwrap o AppDomain.CreateInstance che crea un'istanza di un oggetto in un altro dominio dell'applicazione.
Attività che il gestore eventi può eseguire
Il gestore dell'evento AssemblyResolve riceve il nome visualizzato dell'assembly da caricare nella proprietà ResolveEventArgs.Name. Se il gestore non riconosce il nome dell'assembly, restituisce null (Nothing in Visual Basic, nullptr in Visual C++).
Se il gestore riconosce il nome dell'assembly, può caricare e restituire un assembly che soddisfi la richiesta. Nell'elenco seguente vengono descritti alcuni scenari di esempio.
Se il gestore conosce il percorso di una versione dell'assembly, può caricare l'assembly utilizzando il metodo Assembly.LoadFile o Assembly.LoadFrom e può restituire l'assembly caricato in caso di esito positivo.
Se il gestore ha accesso a un database degli assembly archiviati come matrici di byte, può caricare una matrice di byte utilizzando uno degli overload del metodo Assembly.Load che accetta una matrice di byte.
Il gestore può generare un assembly dinamico e restituirlo.
![]() |
---|
Il gestore deve caricare l'assembly nel contesto di origine del caricamento, nel contesto di caricamento o senza contesto.Se il gestore carica l'assembly nel contesto solo reflection utilizzando il metodo Assembly.ReflectionOnlyLoad o Assembly.ReflectionOnlyLoadFrom, il tentativo di caricamento che ha generato l'evento AssemblyResolve ha esito negativo. |
Il gestore eventi deve restituire un assembly appropriato. Il gestore può analizzare il nome visualizzato dell'assembly richiesto passando il valore della proprietà ResolveEventArgs.Name al costruttore AssemblyName(String). A partire da .NET Framework versione 4, il gestore può utilizzare la proprietà ResolveEventArgs.RequestingAssembly per determinare se la richiesta corrente è una dipendenza di un altro assembly. Queste informazioni consentono di identificare un assembly che soddisfa la dipendenza.
Il gestore eventi può restituire una versione diversa dell'assembly anziché la versione che è stata richiesta.
Nella maggior parte dei casi, l'assembly che viene restituito dal gestore verrà visualizzato nel contesto di caricamento, indipendentemente dal contesto in cui viene caricato dal gestore. Se, ad esempio, il gestore utilizza il metodo Assembly.LoadFrom per caricare un assembly nel contesto di origine del caricamento, l'assembly verrà visualizzato nel contesto di caricamento quando viene restituito dal gestore. Nei seguenti casi, tuttavia, l'assembly viene visualizzato senza contesto quando viene restituito dal gestore:
Il gestore carica un assembly senza contesto.
La proprietà ResolveEventArgs.RequestingAssembly non è null.
L'assembly richiedente, ovvero l'assembly che viene restituito dalla proprietà ResolveEventArgs.RequestingAssembly, è stato caricato senza contesto.
Per ulteriori informazioni sui contesti, vedere l'overload del metodo Assembly.LoadFrom(String).
È possibile caricare più versioni dello stesso assembly nello stesso dominio dell'applicazione. Questa procedura non è consigliata poiché possono verificarsi problemi di assegnazione del tipo. Vedere Procedure consigliate per il caricamento di assembly.
Attività che il gestore eventi non deve eseguire
La regola primaria per la gestione dell'evento AssemblyResolve è quella di non tentare di restituire un assembly che non si riconosce. Quando si scrive il gestore, è necessario conoscere gli assembly che possono causare la generazione dell'evento. Il gestore deve restituire null per gli altri assembly.
![]() |
---|
A partire da .NET Framework 4, l'evento AssemblyResolve viene generato per gli assembly satellite.Questa modifica influisce su un gestore eventi che è stato scritto per una versione precedente di .NET Framework, se il gestore tenta di risolvere tutte le richieste di caricamento dell'assembly.I gestori eventi che ignorano gli assembly non riconoscono non sono interessati dalla modifica. Restituiscono null e vengono seguiti i normali meccanismi di fallback. |
Nel caricamento di un assembly, il gestore eventi non deve utilizzare gli overload del metodo AppDomain.Load o Assembly.Load che possono causare la generazione dell'evento AssemblyResolve in modo ricorsivo poiché può verificarsi un overflow dello stack. Vedere l'elenco fornito in precedenza in questo argomento. Ciò si verifica anche se si fornisce la gestione delle eccezioni per la richiesta di caricamento, poiché non viene generata alcuna eccezione finché non vengono restituiti tutti i gestori eventi. Di conseguenza, il codice seguente genera un overflow dello stack se MyAssembly non viene trovato:
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.
*/