همزمان با ارائه نسخه های اولیه Asp.Net Core ، مایکروسافت، یک IOC Container هم برای آن ارائه کرد تا بدون نیاز به کتابخانه های Third Party همچون Autofac بتوانیم Dependency Injection را به صورت خودکار انجام بدهیم. این Container به صورت پیشفرض در Template پروژه های WPF وجود ندارد. در این مقاله نحوه پیاده سازی Dependency Injection در پروژه های WPF با Net 5. را بررسی می کنیم.

ایجاد یک پروژه WPF با Net 5.

برای ایجاد پروژه جدید در Visual Studio طبق تصویر زیر روی Create a new project کلیک می کنیم.

VS-2019-Create-New-Project

سپس همانند تصویر زیر WPF Application را انتخاب و در ادامه عنوان پروژه و محل ذخیره سازی را انتخاب می کنیم.

Select-Wpf-Template-VS-2019

بعد از ایجاد پروژه می توانید فایل csproj را باز کنید و نسخه دات نت را ببینید:

NET-5-Wpf-TargetFramework

نصب پکیج Microsoft.Extensions.DependencyInjection

برای استفاده از IOC Container ارائه شده توسط تیم دات نت لازم است پکیج Microsoft.Extensions.DependencyInjection را نصب کنید.

Install-Microsoft.Extensions.DependencyInjection-Nuget

پیاده سازی Dependency Injection

اگر به فایل App.xaml توجه کنید، به صورت پیش‌فرض دارای پراپرتی StartupUri است که فرم پیش‌فرض برنامه هنگام اجرا را مشخص می کند.

wpf-app.xaml-StartupUri

برای پیاده سازی Dependency Injection باید این پراپرتی را حذف و بجای آن Startup که یک Event هست را پیاده سازی کنیم.

فایل App.xaml را به صورت زیر ویرایش می کنیم:

wpf-app.xaml-Startup

از این مرحله به بعد بیشتر تمرکزمان روی فایل App.xaml.cs خواهد بود. ابتدا یک پراپرتی از نوع اینترفیس IServiceProvider در این فایل (کلاس) ایجاد می کنیم. سپس در رویداد OnStartup که کمی بالا تر ایجاد کردیم، یک نمونه از کلاس ServiceCollection ایجاد می کنیم. حال متدی با عنوان ConfigureServices ایجاد می کنیم که به عنوان ورودی یک نمونه از کلاس ServiceCollection (که چند لحظه قبل ایجاد کردیم) دریافت می کند. از این متد برای Register کردن سرویس ها استفاده می کنیم. استفاده از این متد باعث می شود کد های مربوط به Register کردن Service ها در متدی جداگانه جمع شده و از شلوغ شدن رویداد جلوگیری شود. برای مثال MainWindow را به صورت AddTransient در آن Register می کنیم.
سپس در ادامه کد های رویداد OnStartup ، متد ConfigureServices را فراخوانی می کنیم و نمونه ایجاد شده از کلاس ServiceCollection به عنوان ورودی به آن می دهیم.

در نهایت با فراخوانی متد BuildServiceProvider از کلاس ServiceCollection و ذخیره خروجی آن در پراپرتی ServiceProvider به پیاده سازی Dependency Injection پایان می دهیم.

کد نهایی به این شکل است:

public partial class App
    {
        public IServiceProvider ServiceProvider { get; private set; }


        private void App_OnStartup(object sender, StartupEventArgs e)
        {
            var serviceCollection = new ServiceCollection();

            ConfigureServices(serviceCollection);

            ServiceProvider = serviceCollection.BuildServiceProvider();
        }

        private void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<MainWindow>();
        }
    }

اکنون می توانیم از پراپرتی ServiceProvider سرویس های مورد نظرمان را دریافت کنیم. توجه داشته باشید که کلاس App.xaml.cs قبل از کانفیگ و بیلد IOC Container ایجاد شده است، پس نمی توانیم سرویس های مورد نیاز آن را از طریق Constructor Injection دریافت کنیم.

برای مثال در ادامه کد Event می توانیم یک نمونه از MainWindow دریافت کرده و متد Show آن را فراخوانی کنیم تا پنجره اصلی برنامه نمایش داده شود:

var mainWindow = ServiceProvider.GetRequiredService<MainWindow>();
            mainWindow.Show();

حال اگر برنامه را اجرا کنیم، خواهیم دید پنجره اصلی نمایش داده می شود. به این شکل IOC Container را در پروژه WPF پیاده سازی کردیم. کد نهایی این کلاس به این صورت خواهد بود.

public partial class App
    {
        public IServiceProvider ServiceProvider { get; private set; }


        private void App_OnStartup(object sender, StartupEventArgs e)
        {
            var serviceCollection = new ServiceCollection();

            ConfigureServices(serviceCollection);

            ServiceProvider = serviceCollection.BuildServiceProvider();

            var mainWindow = ServiceProvider.GetRequiredService<MainWindow>();
            mainWindow.Show();
        }

        private void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<MainWindow>();
        }
    }

در ادامه می توانیم سرویس های مورد نظرمان را در متد ConfigureServices رجیستر کنیم و در محل های مورد نیاز از طریق Constructor Injection دریافت کنیم.

منابع و مطالعه بیشتر

سورس کد پروژه : https://github.com/softamoz/WPF.NET5DIAndConfiguration