Ioc (Inversi kontrol)

Pola umum yang dapat digunakan untuk meningkatkan modularitas dalam basis kode aplikasi menggunakan pola MVVM adalah menggunakan beberapa bentuk inversi kontrol. Salah satu solusi paling umum khususnya adalah menggunakan injeksi dependensi, yang terdiri dari pembuatan sejumlah layanan yang disuntikkan ke kelas backend (yaitu diteruskan sebagai parameter ke konstruktor viewmodel) - ini memungkinkan kode menggunakan layanan ini untuk tidak mengandalkan detail implementasi layanan ini, dan juga memudahkan untuk menukar implementasi konkret layanan ini. Pola ini juga memudahkan untuk membuat fitur khusus platform tersedia untuk kode backend, dengan mengabstraksikannya melalui layanan yang kemudian disuntikkan jika diperlukan.

Toolkit MVVM tidak menyediakan API bawaan untuk memfasilitasi penggunaan pola ini, karena sudah ada pustaka khusus khusus untuk ini seperti Microsoft.Extensions.DependencyInjection paket, yang menyediakan set API DI yang sepenuhnya berfitur dan canggih, dan bertindak sebagai mudah diatur dan digunakan IServiceProvider. Panduan berikut akan merujuk ke pustaka ini dan memberikan serangkaian contoh cara mengintegrasikannya ke dalam aplikasi menggunakan pola MVVM.

API Platform:Ioc

Mengonfigurasi dan mengatasi layanan

Langkah pertama adalah mendeklarasikan IServiceProvider instans, dan untuk menginisialisasi semua layanan yang diperlukan, biasanya saat startup. Misalnya, pada UWP (tetapi pengaturan serupa juga dapat digunakan pada kerangka kerja lain):

public sealed partial class App : Application
{
    public App()
    {
        Services = ConfigureServices();

        this.InitializeComponent();
    }

    /// <summary>
    /// Gets the current <see cref="App"/> instance in use
    /// </summary>
    public new static App Current => (App)Application.Current;

    /// <summary>
    /// Gets the <see cref="IServiceProvider"/> instance to resolve application services.
    /// </summary>
    public IServiceProvider Services { get; }

    /// <summary>
    /// Configures the services for the application.
    /// </summary>
    private static IServiceProvider ConfigureServices()
    {
        var services = new ServiceCollection();

        services.AddSingleton<IFilesService, FilesService>();
        services.AddSingleton<ISettingsService, SettingsService>();
        services.AddSingleton<IClipboardService, ClipboardService>();
        services.AddSingleton<IShareService, ShareService>();
        services.AddSingleton<IEmailService, EmailService>();

        return services.BuildServiceProvider();
    }
}

Di sini properti diinisialisasi Services saat startup, dan semua layanan aplikasi dan viewmodel terdaftar. Ada juga properti baru Current yang dapat digunakan untuk dengan mudah mengakses Services properti dari tampilan lain dalam aplikasi. Contohnya:

IFilesService filesService = App.Current.Services.GetService<IFilesService>();

// Use the files service here...

Aspek utama di sini adalah bahwa setiap layanan mungkin sangat baik menggunakan API khusus platform, tetapi karena semuanya diabstraksi melalui antarmuka yang digunakan kode kami, kita tidak perlu khawatir tentang mereka setiap kali kita hanya menyelesaikan instans dan menggunakannya untuk melakukan operasi.

Injeksi konstruktor

Salah satu fitur canggih yang tersedia adalah "injeksi konstruktor", yang berarti bahwa penyedia layanan DI dapat secara otomatis menyelesaikan dependensi tidak langsung antara layanan terdaftar saat membuat instans jenis yang diminta. Pertimbangkan layanan berikut:

public class FileLogger : IFileLogger
{
    private readonly IFilesService FileService;
    private readonly IConsoleService ConsoleService;

    public FileLogger(
        IFilesService fileService,
        IConsoleService consoleService)
    {
        FileService = fileService;
        ConsoleService = consoleService;
    }

    // Methods for the IFileLogger interface here...
}

Di sini kita memiliki jenis yang FileLogger mengimplementasikan IFileLogger antarmuka, dan membutuhkan IFilesService dan IConsoleService instans. Injeksi konstruktor berarti penyedia layanan DI akan secara otomatis mengumpulkan semua layanan yang diperlukan, seperti:

/// <summary>
/// Configures the services for the application.
/// </summary>
private static IServiceProvider ConfigureServices()
{
    var services = new ServiceCollection();

    services.AddSingleton<IFilesService, FilesService>();
    services.AddSingleton<IConsoleService, ConsoleService>();
    services.AddSingleton<IFileLogger, FileLogger>();

    return services.BuildServiceProvider();
}

// Retrieve a logger service with constructor injection
IFileLogger fileLogger = App.Current.Services.GetService<IFileLogger>();

Penyedia layanan DI akan secara otomatis memeriksa apakah semua layanan yang diperlukan terdaftar, kemudian akan mengambilnya dan memanggil konstruktor untuk jenis beton terdaftar IFileLogger , untuk mendapatkan instans yang akan dikembalikan.

Bagaimana dengan viewmodels?

Penyedia layanan memiliki "layanan" atas namanya, tetapi sebenarnya dapat digunakan untuk menyelesaikan instans kelas apa pun, termasuk viewmodels! Konsep yang sama yang dijelaskan di atas masih berlaku, termasuk injeksi konstruktor. Bayangkan kita memiliki ContactsViewModel jenis, menggunakan dan IContactsServiceIPhoneService instans melalui konstruktornya. Kita bisa memiliki ConfigureServices metode seperti ini:

/// <summary>
/// Configures the services for the application.
/// </summary>
private static IServiceProvider ConfigureServices()
{
    var services = new ServiceCollection();

    // Services
    services.AddSingleton<IContactsService, ContactsService>();
    services.AddSingleton<IPhoneService, PhoneService>();

    // Viewmodels
    services.AddTransient<ContactsViewModel>();

    return services.BuildServiceProvider();
}

Dan kemudian dalam , kami ContactsViewakan menetapkan konteks data sebagai berikut:

public ContactsView()
{
    this.InitializeComponent();
    this.DataContext = App.Current.Services.GetService<ContactsViewModel>();
}

Dokumen lainnya

Untuk informasi selengkapnya tentang Microsoft.Extensions.DependencyInjection, lihat di sini.

Contoh