Résolution des chargements d'assemblys
Le .NET Framework fournit l'événement AppDomain.AssemblyResolve pour les applications qui requièrent un meilleur contrôle du chargement d'assembly. En gérant cet événement, votre application peut charger un assembly dans le contexte de chargement depuis l'extérieur des chemins d'accès de détection normaux, sélectionner la version d'assembly à charger parmi plusieurs, émettre un assembly dynamique et le retourner, et ainsi de suite. Cette rubrique fournit des instructions pour la gestion de l'événement AssemblyResolve.
![]() |
---|
Pour résoudre les chargements d'assemblys dans le contexte ReflectionOnly, utilisez l'événement AppDomain.ReflectionOnlyAssemblyResolve à la place. |
Fonctionnement de l'événement AssemblyResolve
Lorsque vous enregistrez un gestionnaire pour l'événement AssemblyResolve, le gestionnaire est appelé chaque fois que le runtime ne peut pas lier un assembly par nom. Par exemple, l'appel des méthodes suivantes à partir du code utilisateur peut provoquer le déclenchement de l'événement AssemblyResolve :
Une surcharge de la méthode AppDomain.Load ou Assembly.Load dont le premier argument est une chaîne qui représente le nom complet de l'assembly à charger (c'est-à-dire, la chaîne retournée par la propriété Assembly.FullName).
Une surcharge de la méthode AppDomain.Load ou Assembly.Load dont le premier argument est un objet AssemblyName qui identifie l'assembly à charger.
Une surcharge de méthode Assembly.LoadWithPartialName.
Une surcharge de méthode AppDomain.CreateInstance ou AppDomain.CreateInstanceAndUnwrap qui instancie un objet dans un autre domaine d'application.
Opérations effectuées par le gestionnaire d'événements
Le gestionnaire de l'événement AssemblyResolve reçoit le nom complet de l'assembly à charger dans la propriété ResolveEventArgs.Name. Si le gestionnaire ne reconnaît pas le nom de l'assembly, il retourne null (Nothing dans Visual Basic, nullptr dans Visual C++).
Si le gestionnaire reconnaît le nom de l'assembly, il peut charger et retourner un assembly qui satisfait la requête. La liste suivante décrit certains scénarios d'exemple.
Si le gestionnaire connaît l'emplacement d'une version de l'assembly, il peut charger ce dernier à l'aide de la méthode Assembly.LoadFrom ou Assembly.LoadFile et retourner l'assembly chargé si l'opération a réussi.
Si le gestionnaire a accès à une base de données à partir d'assemblys stockés sous forme de tableaux d'octets, il peut charger un tableau d'octets à l'aide de l'une des surcharges de méthode Assembly.Load qui prennent un tableau d'octets.
Le gestionnaire peut générer un assembly dynamique et le retourner.
![]() |
---|
Le gestionnaire doit charger l'assembly dans le contexte LoadFrom, dans le contexte de chargement, ou sans contexte.Si le gestionnaire charge l'assembly dans le contexte ReflectionOnly en utilisant la méthode Assembly.ReflectionOnlyLoad ou Assembly.ReflectionOnlyLoadFrom, la tentative de chargement qui a déclenché l'événement AssemblyResolve échoue. |
Il est de la responsabilité du gestionnaire d'événements de retourner un assembly approprié. Le gestionnaire peut analyser le nom complet de l'assembly demandé en passant la valeur de propriété ResolveEventArgs.Name au constructeur AssemblyName(String). En commençant par .NET Framework version 4, le gestionnaire peut utiliser la propriété ResolveEventArgs.RequestingAssembly pour déterminer si la requête actuelle est une dépendance d'un autre assembly. Ces informations peuvent aider à identifier un assembly qui satisfera la dépendance.
Le gestionnaire d'événements peut retourner une version de l'assembly différente de celle qui a été demandée.
Dans la plupart des cas, l'assembly qui est retourné par le gestionnaire apparaît dans le contexte de chargement, indépendamment du contexte dans lequel le gestionnaire le charge. Par exemple, si le gestionnaire utilise la méthode Assembly.LoadFrom pour charger un assembly dans le contexte LoadFrom, l'assembly apparaît dans le contexte de chargement lorsque le gestionnaire le retourne. Toutefois, dans le cas suivant, l'assembly apparaît sans contexte lorsque le gestionnaire le retourne :
Le gestionnaire charge un assembly sans contexte.
La propriété ResolveEventArgs.RequestingAssembly n'a pas la valeur null.
L'assembly demandeur (c'est-à-dire, l'assembly qui est retourné par la propriété ResolveEventArgs.RequestingAssembly) a été chargé sans contexte.
Pour plus d'informations sur les contextes, consultez la surcharge de la méthode Assembly.LoadFrom(String).
Plusieurs versions du même assembly peuvent être chargées dans le même domaine d'application. Cette pratique n'est pas recommandée, car elle peut entraîner des problèmes d'assignation de type. Consultez Meilleures pratiques pour le chargement d'assembly.
Ce que le gestionnaire d'événements ne doit pas faire
La règle principale pour gérer l'événement AssemblyResolve est que vous ne devez pas essayer de retourner un assembly que vous ne reconnaissez pas. Lorsque vous écrivez le gestionnaire, vous devez savoir quels assemblys peuvent provoquer le déclenchement de l'événement. Votre gestionnaire doit retourner null pour d'autres assemblys.
![]() |
---|
En commençant par .NET Framework 4, l'événement AssemblyResolve est déclenché pour les assemblys satellites.Cette modification affecte un gestionnaire d'événements qui a été écrit pour une version antérieure du .NET Framework, si le gestionnaire tente de résoudre toutes les requêtes de chargement d'assembly.Les gestionnaires d'événements qui ignorent les assemblys qu'ils ne reconnaissent pas ne sont pas affectés par cette modification : Ils retournent la valeur null et les mécanismes de secours normaux sont suivis. |
Lors du chargement d'un assembly, le gestionnaire d'événements ne doit pas utiliser les surcharges de méthode AppDomain.Load ou Assembly.Load qui peuvent provoquer le déclenchement de l'événement AssemblyResolve de manière récursive, car cela peut provoquer un dépassement de capacité de la pile. (Consultez la liste fournie plus haut dans cette rubrique.) Cela se produit même si vous fournissez la gestion des exceptions pour la demande de chargement, car aucune exception n'est levée jusqu'à ce que tous les gestionnaires d'événements aient été retournés. Par conséquent, le code suivant provoque un dépassement de capacité de la pile si MyAssembly est introuvable :
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.
*/