Tentang System.Runtime.Loader.AssemblyLoadContext

Kelas AssemblyLoadContext diperkenalkan di .NET Core dan tidak tersedia di .NET Framework. Artikel ini melengkapi AssemblyLoadContext dokumentasi API dengan informasi konseptual.

Artikel ini relevan dengan pengembang yang menerapkan pemuatan dinamis, terutama pengembang kerangka kerja pemuatan dinamis.

Apa itu AssemblyLoadContext?

Setiap aplikasi .NET 5+ dan .NET Core secara implisit AssemblyLoadContextmenggunakan . Ini adalah penyedia runtime untuk menemukan dan memuat dependensi. Setiap kali dependensi dimuat, AssemblyLoadContext instans dipanggil untuk menemukannya.

  • AssemblyLoadContext menyediakan layanan penemuan, pemuatan, dan penembolokan rakitan terkelola dan dependensi lainnya.
  • Untuk mendukung pemuatan dan pembongkaran kode dinamis, kode ini membuat konteks terisolasi untuk memuat kode dan dependensinya dalam instans mereka sendiri AssemblyLoadContext .

Aturan penerapan versi

Satu AssemblyLoadContext instans terbatas pada pemuatan tepat satu versi per Assemblynama rakitan sederhana. Ketika referensi perakitan diselesaikan terhadap AssemblyLoadContext instans yang sudah memiliki rakitan nama tersebut yang dimuat, versi yang diminta dibandingkan dengan versi yang dimuat. Resolusi hanya akan berhasil jika versi yang dimuat sama atau lebih tinggi dari versi yang diminta.

Kapan Anda memerlukan beberapa instans AssemblyLoadContext?

Pembatasan bahwa satu AssemblyLoadContext instans hanya dapat memuat satu versi rakitan dapat menjadi masalah saat memuat modul kode secara dinamis. Setiap modul dikompilasi secara independen, dan modul dapat bergantung pada versi yang Assemblyberbeda dari . Ini sering menjadi masalah ketika modul yang berbeda bergantung pada versi yang berbeda dari pustaka yang umum digunakan.

Untuk mendukung pemuatan kode secara dinamis, AssemblyLoadContext API menyediakan untuk memuat versi yang Assembly bertentangan dalam aplikasi yang sama. Setiap AssemblyLoadContext instans menyediakan kamus unik yang memetakan masing-masing AssemblyName.Name ke instans tertentu Assembly .

Ini juga menyediakan mekanisme yang nyaman untuk mengelompokkan dependensi yang terkait dengan modul kode untuk dibongkar nanti.

Instans AssemblyLoadContext.Default

AssemblyLoadContext.Default Instans secara otomatis diisi oleh runtime saat startup. Ini menggunakan pemeriksaan default untuk menemukan dan menemukan semua dependensi statis.

Ini memecahkan skenario pemuatan dependensi yang paling umum.

Dependensi dinamis

AssemblyLoadContext memiliki berbagai peristiwa dan fungsi virtual yang dapat ditimpa.

Instans AssemblyLoadContext.Default hanya mendukung pengesampingan peristiwa.

Artikel Algoritma pemuatan rakitan terkelola, algoritma pemuatan rakitan satelit, dan algoritma pemuatan pustaka tidak terkelola (asli) mengacu pada semua peristiwa dan fungsi virtual yang tersedia. Artikel menunjukkan setiap posisi relatif peristiwa dan fungsi dalam algoritma pemuatan. Artikel ini tidak mereprodusi informasi tersebut.

Bagian ini mencakup prinsip-prinsip umum untuk peristiwa dan fungsi yang relevan.

  • Bisa diulang. Kueri untuk dependensi tertentu harus selalu menghasilkan respons yang sama. Instans dependensi yang dimuat yang sama harus dikembalikan. Persyaratan ini sangat mendasar untuk konsistensi cache. Untuk rakitan terkelola khususnya, kami membuat Assembly cache. Kunci cache adalah nama rakitan sederhana, AssemblyName.Name.
  • Biasanya jangan melempar. Diharapkan bahwa fungsi-fungsi ini kembali null daripada melemparkan ketika tidak dapat menemukan dependensi yang diminta. Pelemparan akan secara prematur mengakhiri pencarian dan menyebarluaskan pengecualian kepada pemanggil. Pelemparan harus dibatasi untuk kesalahan tak terduga seperti rakitan yang rusak atau kondisi kehabisan memori.
  • Hindari rekursi. Ketahuilah bahwa fungsi dan penangan ini menerapkan aturan pemuatan untuk menemukan dependensi. Implementasi Anda tidak boleh memanggil API yang memicu rekursi. Kode Anda biasanya harus memanggil fungsi beban AssemblyLoadContext yang memerlukan jalur tertentu atau argumen referensi memori.
  • Muat ke dalam AssemblyLoadContext yang benar. Pilihan tempat memuat dependensi adalah khusus aplikasi. Pilihan diimplementasikan oleh peristiwa dan fungsi ini. Saat kode Anda memanggil fungsi assemblyLoadContext load-by-path memanggilnya pada instans tempat Anda ingin kode dimuat. Beberapa saat mengembalikan null dan membiarkan AssemblyLoadContext.Default menangani beban mungkin menjadi opsi paling sederhana.
  • Waspadalah terhadap balapan utas. Pemuatan dapat dipicu oleh beberapa utas. AssemblyLoadContext menangani balapan utas dengan secara atom menambahkan rakitan ke cache-nya. Instans pecundang ras dibuang. Dalam logika implementasi Anda, jangan tambahkan logika tambahan yang tidak menangani beberapa utas dengan benar.

Bagaimana dependensi dinamis terisolasi?

Setiap AssemblyLoadContext instans mewakili cakupan unik untuk Assembly instans dan Type definisi.

Tidak ada isolasi biner antara dependensi ini. Mereka hanya terisolasi dengan tidak menemukan satu sama lain berdasarkan nama.

Di setiap AssemblyLoadContext:

Dependensi bersama

Dependensi dapat dengan mudah dibagikan antar AssemblyLoadContext instans. Model umum adalah untuk seseorang AssemblyLoadContext untuk memuat dependensi. Yang lain berbagi dependensi dengan menggunakan referensi ke rakitan yang dimuat.

Berbagi ini diperlukan dari rakitan runtime. Rakitan ini hanya dapat dimuat ke AssemblyLoadContext.Defaultdalam . Hal yang sama diperlukan untuk kerangka kerja seperti ASP.NET, , WPFatau WinForms.

Disarankan agar dependensi bersama dimuat ke dalam AssemblyLoadContext.Default. Berbagi ini adalah pola desain umum.

Berbagi diimplementasikan dalam pengkodan instans kustom AssemblyLoadContext . AssemblyLoadContext memiliki berbagai peristiwa dan fungsi virtual yang dapat ditimpa. Ketika salah satu fungsi ini mengembalikan referensi ke Assembly instans yang dimuat dalam instans lain AssemblyLoadContext , Assembly instans dibagikan. Algoritma beban standar menunggak untuk AssemblyLoadContext.Default pemuatan guna menyederhanakan pola berbagi umum. Untuk informasi selengkapnya, lihat Algoritma pemuatan rakitan terkelola.

Masalah konversi jenis

Ketika dua AssemblyLoadContext instans berisi definisi jenis dengan definisi yang sama name, instans tersebut bukan jenis yang sama. Mereka adalah jenis yang sama jika dan hanya jika berasal dari instans yang sama Assembly .

Untuk mempersulit masalah, pesan pengecualian tentang jenis yang tidak cocok ini dapat membingungkan. Jenisnya disebut dalam pesan pengecualian dengan nama jenis sederhananya. Pesan pengecualian umum dalam hal ini adalah formulir:

Objek jenis 'IsolatedType' tidak dapat dikonversi ke tipe 'IsolatedType'.

Men-debug masalah konversi jenis

Mengingat sepasang jenis yang tidak cocok, penting untuk juga mengetahui:

Mengingat dua objek a dan b, mengevaluasi hal berikut dalam debugger akan membantu:

// In debugger look at each assembly's instance, Location, and FullName
a.GetType().Assembly
b.GetType().Assembly
// In debugger look at each AssemblyLoadContext's instance and name
System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(a.GetType().Assembly)
System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(b.GetType().Assembly)

Mengatasi masalah konversi jenis

Ada dua pola desain untuk memecahkan masalah konversi jenis ini.

  1. Gunakan jenis bersama umum. Jenis bersama ini dapat menjadi jenis runtime primitif, atau dapat melibatkan pembuatan jenis bersama baru dalam rakitan bersama. Seringkali jenis bersama adalah antarmuka yang ditentukan dalam rakitan aplikasi. Untuk informasi selengkapnya, baca tentang bagaimana dependensi dibagikan.

  2. Gunakan teknik marshalling untuk mengonversi dari satu jenis ke jenis lainnya.