Bagaimana cara saya menyelesaikan suatu jenis menggunakan kerangka kerja injeksi dependensi built-in ASP.NET Core MVC?
Menyiapkan wadah cukup mudah:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddTransient<ISomeService, SomeConcreteService>();
}
Tetapi bagaimana saya bisa menyelesaikannya ISomeService
tanpa melakukan injeksi? Sebagai contoh, saya ingin melakukan ini:
ISomeService service = services.Resolve<ISomeService>();
Tidak ada metode seperti itu di IServiceCollection
.
ConfigureServices()
metode (denganIServiceCollection
) atau di mana saja dalam aplikasi?Jawaban:
The
IServiceCollection
antarmuka digunakan untuk membangun wadah injeksi ketergantungan. Setelah sepenuhnya dibangun, itu akan dikomposisikan ke sebuahIServiceProvider
instance yang dapat Anda gunakan untuk menyelesaikan layanan. Anda dapat menyuntikkanIServiceProvider
ke dalam kelas apa pun. TheIApplicationBuilder
danHttpContext
kelas dapat memberikan penyedia layanan juga, melalui merekaApplicationServices
atauRequestServices
sifat masing-masing.IServiceProvider
mendefinisikanGetService(Type type)
metode untuk menyelesaikan layanan:Ada juga beberapa metode ekstensi kenyamanan yang tersedia, seperti
serviceProvider.GetService<IFooService>()
(tambahkanusing
untukMicrosoft.Extensions.DependencyInjection
).Menyelesaikan layanan di dalam kelas startup
Dependensi menyuntikkan
Penyedia layanan hosting runtime dapat menyuntikkan layanan tertentu ke konstruktor
Startup
kelas, sepertiIConfiguration
,IWebHostEnvironment
(IHostingEnvironment
dalam versi pra-3.0),ILoggerFactory
danIServiceProvider
. Perhatikan bahwa yang terakhir adalah contoh yang dibangun oleh lapisan hosting dan hanya berisi layanan penting untuk memulai aplikasi .The
ConfigureServices()
Metode tidak memungkinkan layanan suntik, hanya menerima sebuahIServiceCollection
argumen. Ini masuk akal karena diConfigureServices()
situlah Anda mendaftarkan layanan yang diperlukan oleh aplikasi Anda. Namun Anda dapat menggunakan layanan yang disuntikkan di konstruktor startup di sini, misalnya:Setiap layanan yang terdaftar di
ConfigureServices()
kemudian dapat disuntikkan ke dalamConfigure()
metode; Anda dapat menambahkan sejumlah layanan sewenang-wenang setelahIApplicationBuilder
parameter:Mengatasi dependensi secara manual
Jika Anda perlu menyelesaikan layanan secara manual, Anda sebaiknya menggunakan yang
ApplicationServices
disediakan olehIApplicationBuilder
dalamConfigure()
metode:Dimungkinkan untuk lulus dan secara langsung menggunakan nilai
IServiceProvider
dalam konstruktorStartup
kelas Anda , tetapi seperti di atas ini akan berisi subset layanan yang terbatas , dan dengan demikian memiliki utilitas terbatas:Jika Anda harus menyelesaikan layanan dalam
ConfigureServices()
metode ini, diperlukan pendekatan yang berbeda. Anda dapat membangun perantaraIServiceProvider
dariIServiceCollection
instance yang berisi layanan yang telah terdaftar hingga saat itu :Harap dicatat: Secara umum Anda harus menghindari menyelesaikan layanan di dalam
ConfigureServices()
metode, karena ini sebenarnya adalah tempat di mana Anda mengkonfigurasi layanan aplikasi. Terkadang Anda hanya perlu akses ke sebuahIOptions<MyOptions>
instance. Anda bisa mencapai ini dengan mengikat nilai-nilai dariIConfiguration
instance ke instanceMyOptions
(yang pada dasarnya adalah apa yang dilakukan kerangka kerja opsi):Layanan penyelesaian secara manual (alias Service Locator) umumnya dianggap sebagai anti-pola . Meskipun memiliki kasus penggunaannya (untuk kerangka kerja dan / atau lapisan infrastruktur), Anda harus menghindarinya sebanyak mungkin.
sumber
IServiceCollection
menyuntikkan, beberapa kelas yang sedang dibuat secara manual (di luar ruang tengah ware ), scheduler dalam kasus saya, yang secara berkala membutuhkan beberapa layanan untuk menghasilkan dan kirim email.ConfigureServices
dan layanan itu adalah singleton itu akan menjadi singleton yang berbeda dengan yang AndaController
gunakan! Saya berasumsi ini karena menggunakan yang berbedaIServiceProvider
- untuk menghindari hal ini, JANGAN menyelesaikan melaluiBuildServiceProvider
dan sebaliknya memindahkan pencarian Anda dari singletonConfigureServices
keConfigure(..other params, IServiceProvider serviceProvider)
inStartup.cs
IServiceProvider
contoh yang berbeda, itu akan membuat contoh singleton baru. Anda bisa menghindari ini dengan mengembalikan instance penyedia layanan dariConfigureServices
metode sehingga akan menjadi wadah yang digunakan aplikasi Anda juga.collection.BuildServiceProvider();
adalah yang saya butuhkan, terima kasih!Penyelesaian instans secara manual melibatkan penggunaan
IServiceProvider
antarmuka:Mengatasi Ketergantungan pada Startup.ConfigureServices
Menyelesaikan Dependensi dalam Startup.Configure
Menyelesaikan Dependensi dalam Startup. Konfigurasi di ASP.NET Core 3
Menggunakan Layanan Injeksi Runtime
Beberapa jenis dapat disuntikkan sebagai parameter metode:
Menyelesaikan Dependensi dalam Aksi Controller
sumber
GetService
yang generik adalah metode ekstensi diMicrosoft.Extensions.DependencyInjection
namespace.Jika Anda membuat aplikasi dengan templat, Anda akan memiliki sesuatu seperti ini di
Startup
kelas:Anda kemudian dapat menambahkan dependensi di sana, misalnya:
Jika Anda ingin mengakses
ITestService
pada controller Anda, Anda dapat menambahkanIServiceProvider
konstruktor dan itu akan disuntikkan:Kemudian Anda dapat menyelesaikan layanan yang Anda tambahkan:
Perhatikan bahwa untuk menggunakan versi generik Anda harus menyertakan namespace dengan ekstensi:
ITestService.cs
TestService.cs
Startup.cs (ConfigureServices)
HomeController.cs
sumber
Jika Anda hanya perlu menyelesaikan satu dependensi untuk tujuan meneruskannya ke konstruktor dependensi lain yang Anda daftarkan, Anda dapat melakukan ini.
Katakanlah Anda memiliki layanan yang mengambil string dan layanan ISOMS.
Saat Anda mendaftar ini di dalam Startup.cs, Anda harus melakukan ini:
sumber
ISomeService
masih nol untuk saya.Anda bisa menyuntikkan dependensi dalam atribut seperti AuthorizeAttribute dengan cara ini
sumber
Saya tahu ini adalah pertanyaan lama tetapi saya heran bahwa peretasan yang agak jelas dan menjijikkan tidak ada di sini.
Anda dapat mengeksploitasi kemampuan untuk mendefinisikan fungsi ctor Anda sendiri untuk mengambil nilai yang diperlukan dari layanan Anda saat Anda mendefinisikannya ... jelas ini akan dijalankan setiap kali layanan diminta kecuali Anda secara eksplisit menghapus / menghapus dan menambahkan kembali definisi dari layanan ini dalam konstruksi pertama dari aktor yang mengeksploitasi .
Metode ini memiliki keuntungan karena tidak mengharuskan Anda untuk membangun pohon layanan, atau menggunakannya, selama konfigurasi layanan. Anda masih mendefinisikan bagaimana layanan akan dikonfigurasi.
Cara untuk memperbaiki pola ini adalah dengan memberikan
OtherService
dependensi eksplisit padaIServiceINeedToUse
, daripada bergantung secara implisit padanya atau nilai kembalinya metodanya ... atau menyelesaikan dependensi itu secara eksplisit dalam beberapa cara lain.sumber
sumber