Bagikan melalui


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 menggunakan AssemblyLoadContext. Ini adalah penyedia runtime untuk menemukan dan memuat dependensi. Setiap kali dependensi dimuat, AssemblyLoadContext instans dipanggil untuk menemukannya.

  • AssemblyLoadContext menyediakan layanan pengelolaan, pemuatan, dan cache rakitan terkelola dan dependensi lainnya.
  • Untuk mendukung pemuatan dan pembongkaran kode dinamis, konteks terisolasi dibuat untuk memuat kode dan dependensinya dalam instans mereka sendiri AssemblyLoadContext.

Aturan pengelolaan versi

Satu instans AssemblyLoadContext dibatasi untuk memuat tepat satu versi Assembly berdasarkan nama rakitan sederhana. Ketika rujukan assembly diselesaikan terhadap AssemblyLoadContext instans yang sudah memuat assembly dengan nama tersebut, versi yang diminta dibandingkan dengan versi yang sudah dimuat. Resolusi hanya akan berhasil jika versi yang dimuat sama atau lebih tinggi dari versi yang diminta.

Kapan Anda membutuhkan beberapa instance 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 berbagai versi dari sebuah Assembly. 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 memungkinkan pemuatan versi Assembly yang saling 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 ketergantungan yang terkait dengan modul kode untuk dilepaskan nanti.

Instans AssemblyLoadContext.Default

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

Ini memecahkan skenario pemuatan dependensi yang paling umum.

Dependensi dinamis

AssemblyLoadContext memiliki berbagai event dan fungsi virtual yang dapat di-override.

Instans AssemblyLoadContext.Default hanya mendukung menggantikan event.

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.

  • Dapat diulang dengan konsisten. Kueri untuk dependensi tertentu harus selalu menghasilkan respons yang sama. Instans dependensi yang telah dimuat harus sama dan dikembalikan. Persyaratan ini sangat mendasar untuk konsistensi cache. Untuk assembly yang dikelola khususnya, kami membangun cache Assembly. 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 pengendali ini menerapkan aturan pemuatan untuk menentukan lokasi 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 tepat. 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 perlombaan thread. Pemuatan dapat dipicu oleh beberapa utas. AssemblyLoadContext menangani perlombaan utas dengan menambahkan rakitan ke dalam cache-nya secara atom. Instance dari peserta kalah dalam perlombaan dibuang. Dalam logika implementasi Anda, jangan tambahkan logika tambahan yang tidak menangani beberapa utas dengan benar.

Bagaimana dependensi dinamis terisolasi?

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

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 satu AssemblyLoadContext memuat sebuah dependensi. Yang lain berbagi ketergantungan dengan menggunakan referensi ke rakitan yang telah dimuat.

Pembagian ini diperlukan oleh rakitan waktu-nyata. Rakitan-rakitan ini hanya dapat dimuat ke dalam AssemblyLoadContext.Default. Hal yang sama diperlukan untuk kerangka kerja seperti ASP.NET, , WPFatau WinForms.

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

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

Masalah konversi jenis

Ketika dua instans AssemblyLoadContext berisi definisi jenis dengan nama yang sama name, itu 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 berbentuk:

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

Memperbaiki masalah konversi tipe

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 yang sering digunakan bersama. Jenis bersama ini dapat berupa tipe runtime primitif, atau dapat melibatkan pembuatan tipe bersama baru dalam assembly 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.