Partage via


Guide pratique pour inspecter le contenu de l’assembly à l’aide de MetadataLoadContext

L’API de réflexion dans .NET permet par défaut aux développeurs d’inspecter le contenu des assemblys chargés dans le contexte d’exécution principal. Toutefois, il est parfois impossible de charger un assembly dans le contexte d’exécution, par exemple, car il a été compilé pour une autre architecture de plateforme ou de processeur, ou il s’agit d’un assembly de référence. L’API System.Reflection.MetadataLoadContext vous permet de charger et d’inspecter ces assemblys. Les assemblys chargés dans le MetadataLoadContext fichier sont traités uniquement comme des métadonnées, c’est-à-dire que vous pouvez examiner les types dans l’assembly, mais vous ne pouvez pas exécuter de code contenu dans celui-ci. Contrairement au contexte d’exécution principal, MetadataLoadContext ne charge pas automatiquement les dépendances à partir du répertoire actuel ; au lieu de cela, il utilise la logique de liaison personnalisée fournie par le MetadataAssemblyResolver passé.

Prerequisites

Pour utiliser MetadataLoadContext, installez le package NuGet System.Reflection.MetadataLoadContext . Il est pris en charge sur n’importe quel framework cible conforme à .NET Standard 2.0, par exemple .NET Core 2.0 ou .NET Framework 4.6.1.

Créer MetadataAssemblyResolver pour MetadataLoadContext

La création de l’instance MetadataLoadContext nécessite la fourniture de l’instance du MetadataAssemblyResolver. La méthode la plus simple pour en fournir un consiste à utiliser le PathAssemblyResolver, qui résout les assemblys de la collection donnée de chaînes de chemin d’assembly. Cette collection doit inclure, outre les assemblies que vous souhaitez inspecter, toutes les dépendances nécessaires. Par exemple, pour lire l’attribut personnalisé situé dans un assembly externe, vous devez intégrer cet assembly, sinon une exception sera levée. Dans la plupart des cas, vous devez inclure au moins l’assembly principal, autrement dit, l’assembly contenant des types système intégrés, tels que System.Object. Le code suivant montre comment créer PathAssemblyResolver en utilisant la collection composée de l’assembly inspecté et de l’assembly principal du runtime actuel.

var resolver = new PathAssemblyResolver(new string[] { "ExampleAssembly.dll", typeof(object).Assembly.Location });

Si vous avez besoin d’accéder à tous les types BCL, vous pouvez inclure tous les assemblys d’exécution dans la collection. Le code suivant montre comment créer le PathAssemblyResolver en utilisant la collection composée de l’assembly inspecté et de tous les assemblys de l’environnement d’exécution actuel :

// Get the array of runtime assemblies.
string[] runtimeAssemblies = Directory.GetFiles(RuntimeEnvironment.GetRuntimeDirectory(), "*.dll");

// Create the list of assembly paths consisting of runtime assemblies and the inspected assembly.
var paths = new List<string>(runtimeAssemblies);
paths.Add("ExampleAssembly.dll");

// Create PathAssemblyResolver that can resolve assemblies using the created list.
var resolver = new PathAssemblyResolver(paths);

Créer MetadataLoadContext

Pour créer le MetadataLoadContext, appelez son constructeur MetadataLoadContext(MetadataAssemblyResolver, String), en passant le MetadataAssemblyResolver précédemment créé comme premier paramètre et le nom de l'assembleur principal comme deuxième paramètre. Vous pouvez omettre le nom de l’assembly principal, auquel cas le constructeur tente d’utiliser des noms par défaut : « mscorlib », « System.Runtime » ou « netstandard ».

Une fois que vous avez créé le contexte, vous pouvez charger des assemblys dans celui-ci à l’aide de méthodes telles que LoadFromAssemblyPath. Vous pouvez utiliser toutes les API de réflexion sur les assemblys chargés, sauf ceux qui impliquent l’exécution du code. La méthode GetCustomAttributes implique l'exécution des constructeurs. Utilisez donc la méthode GetCustomAttributesData à la place lorsque vous devez examiner les attributs personnalisés dans le MetadataLoadContext.

L’exemple de code suivant crée MetadataLoadContext, charge l’assembly dans celui-ci et génère des attributs d’assembly dans la console :

var mlc = new MetadataLoadContext(resolver);

using (mlc)
{
    // Load assembly into MetadataLoadContext.
    Assembly assembly = mlc.LoadFromAssemblyPath("ExampleAssembly.dll");
    AssemblyName name = assembly.GetName();

    // Print assembly attribute information.
    Console.WriteLine($"{name.Name} has following attributes: ");

    foreach (CustomAttributeData attr in assembly.GetCustomAttributesData())
    {
        try
        {
            Console.WriteLine(attr.AttributeType);
        }
        catch (FileNotFoundException ex)
        {
            // We are missing the required dependency assembly.
            Console.WriteLine($"Error while getting attribute type: {ex.Message}");
        }
    }
}

Si vous devez tester l'égalité ou l'affectation des types dans MetadataLoadContext, utilisez uniquement les objets de type chargés dans ce contexte. Le mélange de types MetadataLoadContext avec des types à l'exécution n’est pas pris en charge. Par exemple, considérez un type testedType dans MetadataLoadContext. Si vous devez tester si un autre type est assignable à partir de celui-ci, n’utilisez pas de code comme typeof(MyType).IsAssignableFrom(testedType). Utilisez du code comme celui-ci à la place :

Assembly matchAssembly = mlc.LoadFromAssemblyPath(typeof(MyType).Assembly.Location);
Type matchType = assembly.GetType(typeof(MyType).FullName!)!;

if (matchType.IsAssignableFrom(testedType))
{
    Console.WriteLine($"{nameof(matchType)} is assignable from {nameof(testedType)}");
}

Example

Pour obtenir un exemple de code complet, consultez l’exemple Inspecter le contenu de l’assembly à l’aide de l’exemple MetadataLoadContext.

Voir aussi