Cara: Memeriksa konten perakitan menggunakan MetadataLoadContext

API refleksi di .NET secara default memungkinkan pengembang untuk memeriksa konten rakitan yang dimuat ke dalam konteks eksekusi utama. Namun, terkadang tidak dimungkinkan untuk memuat rakitan ke dalam konteks eksekusi, misalnya, karena dikompilasi untuk platform atau arsitektur prosesor lain, atau itu adalah perakitan referensi. System.Reflection.MetadataLoadContext API memungkinkan Anda memuat dan memeriksa rakitan seperti itu. Rakitan yang dimuat ke dalam MetadataLoadContext diperlakukan hanya sebagai metadata, yaitu, Anda dapat memeriksa jenis dalam rakitan, tetapi Anda tidak dapat menjalankan kode apa pun yang terkandung di dalamnya. Tidak seperti konteks eksekusi utama, MetadataLoadContext tidak secara otomatis memuat dependensi dari direktori saat ini; sebaliknya, ia menggunakan logika pengikatan kustom yang disediakan oleh MetadataAssemblyResolver yang diteruskan kepadanya.

Prasyarat

Untuk menggunakan MetadataLoadContext, instal paket System.Reflection.MetadataLoadContext NuGet . Ini didukung pada kerangka kerja target yang mematuhi .NET Standard 2.0, misalnya, .NET Core 2.0 atau .NET Framework 4.6.1.

Membuat MetadataAssemblyResolver untuk MetadataLoadContext

MetadataLoadContext Membuat MetadataLoadContext memerlukan penyediaan instans dari MetadataAssemblyResolver. Cara paling sederhana untuk menyediakannya adalah dengan menggunakan PathAssemblyResolver, yang menyelesaikan rakitan dari kumpulan string jalur rakitan yang diberikan. Koleksi ini, selain rakitan yang ingin Anda periksa secara langsung, juga harus mencakup semua dependensi yang diperlukan. Misalnya, untuk membaca atribut kustom yang terletak di rakitan eksternal, Anda harus menyertakan rakitan tersebut, jika tidak pengecualian akan terjadi. Dalam kebanyakan kasus, Anda harus menyertakan setidaknya perakitan inti, yaitu perakitan yang berisi jenis sistem bawaan, seperti System.Object. Kode berikut menunjukkan cara membuat PathAssemblyResolver menggunakan koleksi yang terdiri dari rakitan yang diperiksa dan rakitan inti runtime saat ini:

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

Jika Anda memerlukan akses ke semua jenis BCL, Anda dapat menyertakan semua rakitan runtime dalam koleksi. Kode berikut menunjukkan cara membuat PathAssemblyResolver menggunakan koleksi yang terdiri dari rakitan yang diperiksa dan semua rakitan runtime yang sedang berjalan:

// 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);

Membuat MetadataLoadContext

Untuk membuat MetadataLoadContext, panggil konstruktornya MetadataLoadContext(MetadataAssemblyResolver, String), dengan meneruskan MetadataAssemblyResolver yang telah dibuat sebelumnya sebagai parameter pertama dan nama rakitan inti sebagai parameter kedua. Anda dapat menghilangkan nama rakitan inti, dalam hal ini konstruktor akan mencoba menggunakan nama default: "mscorlib", "System.Runtime", atau "netstandard".

Setelah membuat konteks, Anda dapat memuat rakitan ke dalamnya menggunakan metode seperti LoadFromAssemblyPath. Anda dapat menggunakan semua API refleksi pada rakitan yang dimuat kecuali yang melibatkan eksekusi kode. Metode GetCustomAttributes memang melibatkan pelaksanaan konstruktor, jadi gunakan metode GetCustomAttributesData sebagai gantinya ketika Anda perlu memeriksa atribut kustom dalam MetadataLoadContext.

Sampel kode berikut membuat MetadataLoadContext, memuat rakitan ke dalamnya, dan menghasilkan atribut perakitan ke dalam konsol:

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}");
        }
    }
}

Jika Anda perlu menguji tipe untuk kesetaraan atau dapat ditugaskan, hanya gunakan objek tipe yang dimuat ke dalam konteks tersebut MetadataLoadContext. Jenis MetadataLoadContext yang dicampur dengan jenis runtime tidak didukung. Misalnya, pertimbangkan jenis testedType di MetadataLoadContext. Jika Anda perlu menguji apakah jenis lain dapat ditetapkan darinya, jangan gunakan kode seperti typeof(MyType).IsAssignableFrom(testedType). Gunakan kode seperti ini sebagai gantinya:

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

Untuk contoh kode lengkap, lihat sampel Periksa konten rakitan menggunakan MetadataLoadContext.

Lihat juga