Bagikan melalui


Injeksi dependensi

Tip

Konten ini adalah kutipan dari eBook, Pola Aplikasi Perusahaan Menggunakan .NET MAUI, tersedia di .NET Docs atau sebagai PDF gratis yang dapat diunduh yang dapat dibaca secara offline.

Pola Aplikasi Perusahaan Menggunakan thumbnail sampul .NET MAUI eBook.

Biasanya, konstruktor kelas dipanggil saat membuat instans objek, dan nilai apa pun yang dibutuhkan objek diteruskan sebagai argumen ke konstruktor. Ini adalah contoh injeksi dependensi yang dikenal sebagai injeksi konstruktor. Dependensi yang dibutuhkan objek disuntikkan ke dalam konstruktor.

Dengan menentukan dependensi sebagai jenis antarmuka, injeksi dependensi memungkinkan pemisahan jenis beton dari kode yang bergantung pada jenis ini. Ini umumnya menggunakan kontainer yang menyimpan daftar pendaftaran dan pemetaan antara antarmuka dan jenis abstrak, dan jenis beton yang mengimplementasikan atau memperluas jenis ini.

Ada juga jenis injeksi dependensi lainnya, seperti injeksi setter properti dan injeksi panggilan metode, tetapi kurang umum terlihat. Oleh karena itu, bab ini hanya akan berfokus pada melakukan injeksi konstruktor dengan kontainer injeksi dependensi.

Pengantar injeksi dependensi

Injeksi dependensi adalah versi khusus dari pola Inversion of Control (IoC), di mana kekhawatiran yang terbalik adalah proses mendapatkan dependensi yang diperlukan. Dengan injeksi dependensi, kelas lain bertanggung jawab untuk menyuntikkan dependensi ke dalam objek saat runtime. Contoh kode berikut menunjukkan bagaimana ProfileViewModel kelas disusun saat menggunakan injeksi dependensi:

private readonly ISettingsService _settingsService;
private readonly IAppEnvironmentService _appEnvironmentService;

public ProfileViewModel(
    IAppEnvironmentService appEnvironmentService,
    IDialogService dialogService, 
    INavigationService navigationService, 
    ISettingsService settingsService)
    : base(dialogService, navigationService, settingsService)
{
    _appEnvironmentService = appEnvironmentService;
    _settingsService = settingsService;

    // Omitted for brevity
}

ProfileViewModel Konstruktor menerima beberapa instans objek antarmuka sebagai argumen yang disuntikkan oleh kelas lain. Satu-satunya ProfileViewModel dependensi di kelas adalah pada jenis antarmuka. Oleh karena itu, ProfileViewModel kelas tidak memiliki pengetahuan tentang kelas yang bertanggung jawab untuk membuat instans objek antarmuka. Kelas yang bertanggung jawab untuk membuat instans objek antarmuka, dan memasukkannya ke ProfileViewModel dalam kelas, dikenal sebagai kontainer injeksi dependensi.

Kontainer injeksi dependensi mengurangi konektor antar objek dengan menyediakan fasilitas untuk membuat instans kelas dan mengelola masa pakainya berdasarkan konfigurasi kontainer. Selama pembuatan objek, kontainer menyuntikkan dependensi apa pun yang diperlukan objek ke dalamnya. Jika dependensi tersebut belum dibuat, kontainer akan membuat dan menyelesaikan dependensinya terlebih dahulu.

Ada beberapa keuntungan menggunakan kontainer injeksi dependensi:

  • Kontainer menghilangkan kebutuhan kelas untuk menemukan dependensinya dan mengelola masa pakainya.
  • Kontainer memungkinkan pemetaan dependensi yang diimplementasikan tanpa memengaruhi kelas.
  • Kontainer memfasilitasi uji coba dengan memungkinkan dependensi ditiru.
  • Kontainer meningkatkan keberlanjutan dengan memungkinkan kelas baru ditambahkan dengan mudah ke aplikasi.

Dalam konteks aplikasi .NET MAUI yang menggunakan MVVM, kontainer injeksi dependensi biasanya akan digunakan untuk mendaftarkan dan menyelesaikan tampilan, mendaftarkan dan menyelesaikan model tampilan, dan untuk mendaftarkan layanan dan menyuntikkannya ke model tampilan.

Ada banyak kontainer injeksi dependensi yang tersedia di .NET; aplikasi multi-platform eShop menggunakan Microsoft.Extensions.DependencyInjection untuk mengelola instansiasi tampilan, melihat model, dan kelas layanan di aplikasi. Microsoft.Extensions.DependencyInjection memfasilitasi pembuatan aplikasi yang digabungkan secara longgar, dan menyediakan semua fitur yang umum ditemukan dalam kontainer injeksi dependensi, termasuk metode untuk mendaftarkan pemetaan jenis dan instans objek, menyelesaikan objek, mengelola masa pakai objek, dan menyuntikkan objek dependen ke dalam konstruktor objek yang diselesaikannya. Untuk informasi selengkapnya tentang Microsoft.Extensions.DependencyInjection, lihat Injeksi dependensi di .NET.

Di .NET MAUI, MauiProgram kelas akan memanggil ke metode CreateMauiApp untuk membuat MauiAppBuilder objek. Objek MauiAppBuilder memiliki Services properti jenis IServiceCollection, yang menyediakan tempat untuk mendaftarkan komponen kami, seperti tampilan, melihat model, dan layanan untuk injeksi dependensi. Komponen apa pun yang terdaftar dengan Services properti akan diberikan ke kontainer injeksi dependensi ketika metode dipanggil MauiAppBuilder.Build .

Pada runtime, kontainer harus mengetahui implementasi layanan mana yang diminta untuk membuat instans untuk objek yang diminta. Di aplikasi multi-platform eShop, IAppEnvironmentServiceantarmuka , , IDialogServiceINavigationService, dan ISettingsService perlu diselesaikan sebelum dapat membuat instans ProfileViewModel objek. Ini melibatkan kontainer yang melakukan tindakan berikut:

  • Memutuskan cara membuat instans objek yang mengimplementasikan antarmuka. Ini dikenal sebagai pendaftaran.
  • Membuat instans objek yang mengimplementasikan antarmuka dan objek yang ProfileViewModel diperlukan. Ini dikenal sebagai resolusi.

Akhirnya, aplikasi akan selesai menggunakan ProfileViewModel objek , dan akan tersedia untuk pengumpulan sampah. Pada titik ini, pengumpul sampah harus membuang implementasi antarmuka berumur pendek jika kelas lain tidak berbagi instans yang sama.

Pendaftaran

Sebelum dependensi dapat disuntikkan ke dalam objek, jenis dependensi harus terlebih dahulu didaftarkan ke kontainer. Mendaftarkan jenis melibatkan meneruskan kontainer antarmuka dan jenis konkret yang mengimplementasikan antarmuka.

Ada dua cara mendaftarkan jenis dan objek dalam kontainer melalui kode:

  • Daftarkan jenis atau pemetaan dengan kontainer. Ini dikenal sebagai pendaftaran sementara. Jika diperlukan, kontainer akan membangun instans dari jenis yang ditentukan.
  • Daftarkan objek yang ada dalam kontainer sebagai singleton. Jika diperlukan, kontainer akan mengembalikan referensi ke objek yang ada.

Catatan

Kontainer injeksi dependensi tidak selalu cocok. Injeksi dependensi memperkenalkan kompleksitas dan persyaratan tambahan yang mungkin tidak sesuai atau berguna untuk aplikasi kecil. Jika kelas tidak memiliki dependensi apa pun, atau bukan dependensi untuk jenis lain, mungkin tidak masuk akal untuk memasukkannya ke dalam kontainer. Selain itu, jika kelas memiliki satu set dependensi yang terintegrasi dengan jenis dan tidak akan pernah berubah, mungkin tidak masuk akal untuk memasukkannya ke dalam kontainer.

Pendaftaran jenis yang memerlukan injeksi dependensi harus dilakukan dalam satu metode dalam aplikasi. Metode ini harus dipanggil lebih awal dalam siklus hidup aplikasi untuk memastikannya mengetahui dependensi antara kelasnya. Aplikasi multi-platform eShop melakukan metode ini MauiProgram.CreateMauiApp . Contoh kode berikut menunjukkan bagaimana aplikasi multi-platform eShop mendeklarasikan CreateMauiApp di MauiProgram kelas :

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
        => MauiApp.CreateBuilder()
            .UseMauiApp<App>()
            // Omitted for brevity            
            .RegisterAppServices()
            .RegisterViewModels()
            .RegisterViews()
            .Build();
}

Metode ini MauiApp.CreateBuilder membuat MauiAppBuilder objek yang dapat kita gunakan untuk mendaftarkan dependensi kita. Banyak dependensi dalam aplikasi multi-platform eShop perlu didaftarkan, sehingga metode RegisterAppServicesekstensi , , RegisterViewModelsdan RegisterViews dibuat untuk membantu menyediakan alur kerja pendaftaran yang terorganisir dan dapat dipertahankan. Kode berikut menunjukkan RegisterViewModels metode :

public static MauiAppBuilder RegisterViewModels(this MauiAppBuilder mauiAppBuilder)
{
    mauiAppBuilder.Services.AddSingleton<ViewModels.MainViewModel>();
    mauiAppBuilder.Services.AddSingleton<ViewModels.LoginViewModel>();
    mauiAppBuilder.Services.AddSingleton<ViewModels.BasketViewModel>();
    mauiAppBuilder.Services.AddSingleton<ViewModels.CatalogViewModel>();
    mauiAppBuilder.Services.AddSingleton<ViewModels.ProfileViewModel>();

    mauiAppBuilder.Services.AddTransient<ViewModels.CheckoutViewModel>();
    mauiAppBuilder.Services.AddTransient<ViewModels.OrderDetailViewModel>();
    mauiAppBuilder.Services.AddTransient<ViewModels.SettingsViewModel>();
    mauiAppBuilder.Services.AddTransient<ViewModels.CampaignViewModel>();
    mauiAppBuilder.Services.AddTransient<ViewModels.CampaignDetailsViewModel>();

    return mauiAppBuilder;
}

Metode ini menerima instans MauiAppBuilder, dan kita dapat menggunakan Services properti untuk mendaftarkan model tampilan kita. Tergantung pada kebutuhan aplikasi Anda, Anda mungkin perlu menambahkan layanan dengan masa pakai yang berbeda. Tabel berikut ini menyediakan informasi tentang kapan Anda mungkin ingin memilih masa pakai pendaftaran yang berbeda ini:

Metode Deskripsi
AddSingleton<T> Akan membuat satu instans objek yang akan tetap selama masa pakai aplikasi.
AddTransient<T> Akan membuat instans baru objek saat diminta selama resolusi. Objek sementara tidak memiliki masa pakai yang telah ditentukan sebelumnya, tetapi biasanya akan mengikuti masa pakai host mereka.

Catatan

Model tampilan tidak mewarisi dari antarmuka, sehingga mereka hanya membutuhkan jenis konkret yang disediakan untuk AddSingleton<T> metode dan AddTransient<T> .

CatalogViewModel digunakan di dekat akar aplikasi dan harus selalu tersedia, jadi mendaftarkannya AddSingleton<T> bermanfaat. Model tampilan lain, seperti CheckoutViewModel dan OrderDetailViewModel secara situasional dinavigasi ke atau digunakan nanti dalam aplikasi. Misalkan Anda tahu bahwa Anda memiliki komponen yang mungkin tidak selalu digunakan. Dalam hal ini, jika itu adalah memori atau intensif komputasi atau membutuhkan data just-in-time, itu mungkin kandidat yang lebih baik untuk AddTransient<T> pendaftaran.

Cara umum lain untuk menambahkan layanan adalah menggunakan AddSingleton<TService, TImplementation> metode dan AddTransient<TService, TImplementation> . Metode ini mengambil dua jenis input: definisi antarmuka dan implementasi konkret. Jenis pendaftaran ini paling baik untuk kasus di mana Anda menerapkan layanan berdasarkan antarmuka. Dalam contoh kode di bawah ini, kami mendaftarkan antarmuka kami ISettingsService menggunakan SettingsService implementasi:

public static MauiAppBuilder RegisterAppServices(this MauiAppBuilder mauiAppBuilder)
{
    mauiAppBuilder.Services.AddSingleton<ISettingsService, SettingsService>();
    // Omitted for brevity...
}

Setelah semua layanan terdaftar, MauiAppBuilder.Build metode harus dipanggil untuk membuat dan MauiApp mengisi kontainer injeksi dependensi kami dengan semua layanan terdaftar.

Penting

Build Setelah metode dipanggil, kontainer injeksi dependensi tidak dapat diubah dan tidak dapat lagi diperbarui atau dimodifikasi. Pastikan bahwa semua layanan yang Anda butuhkan dalam aplikasi Anda telah didaftarkan sebelum Anda memanggil Build.

Resolusi

Setelah jenis terdaftar, jenis dapat diselesaikan atau disuntikkan sebagai dependensi. Ketika jenis sedang diselesaikan, dan kontainer perlu membuat instans baru, kontainer tersebut menyuntikkan dependensi apa pun ke dalam instans.

Umumnya, ketika jenis diselesaikan, salah satu dari tiga hal terjadi:

  1. Jika jenis belum terdaftar, kontainer akan melemparkan pengecualian.
  2. Jika jenis telah didaftarkan sebagai singleton, kontainer mengembalikan instans singleton. Jika ini adalah pertama kalinya jenis dipanggil, kontainer membuatnya jika diperlukan dan mempertahankan referensi ke dalamnya.
  3. Jika jenis telah didaftarkan sebagai sementara, kontainer mengembalikan instans baru dan tidak mempertahankan referensi ke dalamnya.

.NET MAUI menawarkan sejumlah cara untuk menyelesaikan komponen terdaftar berdasarkan kebutuhan Anda. Cara paling langsung untuk mendapatkan akses ke kontainer injeksi dependensi adalah dari Element menggunakan Handler.MauiContext.Services. Contohnya ditunjukkan di bawah ini:

var settingsService = this.Handler.MauiContext.Services.GetServices<ISettingsService>();

Ini dapat membantu jika Anda perlu menyelesaikan layanan dari dalam Element atau dari luar konstruktor Anda Element.

Perhatian

Ada kemungkinan bahwa Handler properti Anda Element mungkin null, jadi ketahuilah bahwa Anda mungkin perlu menangani situasi tersebut. Untuk informasi selengkapnya, silakan merujuk ke siklus hidup Handler di Pusat Dokumentasi Microsoft.

Jika menggunakan Shell kontrol untuk .NET MAUI, secara implisit akan memanggil kontainer injeksi dependensi untuk membuat objek kami selama navigasi. Saat menyiapkan kontrol kami Shell , Routing.RegisterRoute metode akan mengikat jalur rute ke seperti yang View ditunjukkan pada contoh di bawah ini:

Routing.RegisterRoute("Filter", typeof(FiltersView));

Selama Shell navigasi, ia akan mencari pendaftaran FiltersView, dan jika ada yang ditemukan, itu akan membuat tampilan itu dan menyuntikkan dependensi apa pun ke dalam konstruktor. Seperti yang ditunjukkan dalam contoh kode di bawah ini, CatalogViewModel akan disuntikkan ke dalam FiltersView:

namespace eShop.Views;

public partial class FiltersView : ContentPage
{
    public FiltersView(CatalogViewModel viewModel)
    {
        BindingContext = viewModel;

        InitializeComponent();
    }
}

Tip

Kontainer injeksi dependensi sangat bagus untuk membuat instans model tampilan. Jika model tampilan memiliki dependensi, model tampilan akan menangani pembuatan dan injeksi layanan yang diperlukan. Pastikan Anda mendaftarkan model tampilan dan dependensi apa pun yang mungkin mereka miliki dengan CreateMauiApp metode di MauiProgram kelas .

Ringkasan

Injeksi dependensi memungkinkan pemisahan jenis beton dari kode yang bergantung pada jenis ini. Biasanya menggunakan kontainer yang menyimpan daftar pendaftaran dan pemetaan antara antarmuka dan jenis abstrak, dan jenis beton yang mengimplementasikan atau memperluas jenis ini.

Microsoft.Extensions.DependencyInjection memfasilitasi pembuatan aplikasi yang digabungkan secara longgar dan menyediakan semua fitur yang umum ditemukan dalam kontainer injeksi dependensi, termasuk metode untuk mendaftarkan pemetaan jenis dan instans objek, menyelesaikan objek, mengelola masa pakai objek, dan menyuntikkan objek dependen ke dalam konstruktor objek yang diselesaikannya.