در دو مقاله قبلی در مورد پیاده سازی Dependency Injection و Configuration در WPF صحبت کردیم. در Net. مفهومی با عنوان Generic Host داریم که می تواند شامل تنظیماتی پیشفرض برای Logging و Configuration و Dependency Injection باشد. همچنین از آن برای مدیریت Life Time برنامه یا Application می توان استفاده کرد.

در این مقاله از Net Generic Host. صرفا برای پیاده سازی Logging و Configuration و Dependency Injection در پروژه های WPF استفاده خواهیم کرد. البته کاربرد های بیشتری هم دارد. برای مثال در Template مربوط به Worker Service از Net Generic Host. برای مدیریت Life Time برنامه و Hosted Service ها استفاده می شود. در مورد Net Generic Host. و Hosted Service ها در آینده مقالاتی خواهم نوشت.

برای شروع، یک پروژه WPF در دات نت بسازید و سپس ادامه مقاله را مطالعه کنید.

نصب Package لازم برای پیاده سازی Net Generic Host.

برای پیاده سازی و استفاده از Host لازم است پکیج Microsoft.Extensions.Hosting را از پنجره Manage Nuget Packages نصب کنید. اگر به صفحه این پکیج در nuget.org مراجعه کنید خواهید دید، این پکیج به بسیاری از پکیج های دیگر همچون Microsoft.Extensions.Configuration یا Microsoft.Extensions.DependencyInjection وابسته است.

پیاده سازی Net Generic Host. در فایل App.xaml.cs

ابتدا در فایل App.xaml پراپرتی StartupUri را حذف می کنیم. سپس در کلاس App.xaml.cs یک فیلد Private از نوع IHost ایجاد می کنیم. در سازنده کلاس، این فیلد را با استفاده از یک متد Static از کلاس Host با عنوان CreateDefaultBuilder مقدار دهی می کنیم. این متد وظیفه ایجاد یک IHostBuilder را دارد که با صدا زدن متد Build یک نمونه از Host ایجاد و در فیلد موردنظر رفرنس داده می شود. پس از ایجاد Host از طریق این شی به Logging و Configuration و Dependency Injection دسرسی داریم.

using System.Windows;
using Microsoft.Extensions.Hosting;

namespace WPF.NETGenericHost
{

    public partial class App : Application
    {
        private readonly IHost _host;

        public App()
        {
            _host = Host.CreateDefaultBuilder()
                .Build();
        }
    }
}

استفاده از Dependency Injection در WPF با Net Generic Host.

در فایل App.xaml.cs یک متد به شکل زیر ایجاد می کنیم:

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

سپس متد ConfigureServices را قبل از Build کردن به شکل زیر استفاده می کنیم:

_host = Host.CreateDefaultBuilder()
                .ConfigureServices((context, services) => MyAppConfigureServices(context.Configuration, services))
                .Build();

بعد از این میتونیم سرویس های مورد نظرمون رو در این متد یعنی MyAppConfigureServices رجیستر کنیم. برای مثال در فایل App.xaml رویداد Startup را ایجاد و در کلاس App.xaml.cs به شکل زیر پیاده سازی می کنیم:

private void App_OnStartup(object sender, StartupEventArgs e)
        {
            _host.Services.GetRequiredService<MainWindow>().Show();
        }

با انجام این کار، بعد از اجرای برنامه Main Window نمایش داده میشود.

استفاده از Configuration در WPF با Net Generic Host.

ابتدا فایل appsettings.json را با محتوای زیر ایجاد می کنیم:

{
  "MainWindowText": "Hello .Net Generic Host!!!"
}

این فایل در سورس کد این مقاله وجود ندارد و باید دستی ایجاد شود. سپس با قرار دادن کد زیر در فایل csproj تنظیم می کنیم که در صورت تغییر به Out Put Directory کپی شود. (محل فایل اجرایی برنامه)

<ItemGroup>
   <None Update="appsettings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
   </None>
</ItemGroup>

در فایل MainWindow.xaml یک Text Box ایجاد می کنیم:

<Window x:Class="WPF.NETGenericHost.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow"
        Height="450"
        Width="800">
    <Grid>
        <TextBox Name="TextBox" />
    </Grid>
</Window>

و در فایل MainWindow.xaml.cs تغییراتی به این شکل ایجاد می کنیم:

using System.Windows;
using Microsoft.Extensions.Configuration;

namespace WPF.NETGenericHost
{
    public partial class MainWindow : Window
    {
        public MainWindow(IConfiguration configuration)
        {
            InitializeComponent();

            TextBox.Text = configuration.GetSection("MainWindowText").Value;
        }
    }
}

با اجرای برنامه خواهید دید متن “Hello .Net Generic Host!!!” نمایش داده می شود.

استفاده از Logging در WPF با Net Generic Host.

با اندکی تغییر در کلاس MainWindow.xaml.cs از Logging هم در این پنجره استفاده می کنیم:

using System.Windows;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace WPF.NETGenericHost
{
    public partial class MainWindow : Window
    {
        public MainWindow(IConfiguration configuration, ILogger<MainWindow> logger)
        {
            InitializeComponent();

            TextBox.Text = configuration.GetSection("MainWindowText").Value;

            logger.LogCritical($"{nameof(MainWindow)} is Loaded!!!!");
        }
    }
}

بعد از انجام این تغییر و اجرای برنامه در حالت دیباگ، متن مورد نظر در پنجره Output در Visual Studio ظاهر خواهد شد.

Worker Service در Net Generic Host.

بجز Dependency Injection, Logging و Configuration از جنریک هاست در دات نت برای اجرای پیاده سازی های IHostedService نیز استفاده می شود. برای مثال در پروژه های ASP.NET Core ، وب سرویس داخلی دات نت یعنی Kestrel به عنوان یک IHostedService توسط جنریک هاست دات نت اجرا می شود.

اما این کاربرد شاید در پروژه های WPF خیلی مرسوم و مورد نیاز نباشد، پس در این مقاله در این مورد صحبت نمی کنیم. اما اگر در سایر مقالات یا پیاده سازی ها، متد های StartAsync یا Run (این متد در Program.cs پروژه های ASP.NET Core دیده میشه) رو دیدید، بدونید این متد وظیفه داره Worker Service ها که پیاده سازی IHostedService هستند رو اجرا کنه. همینطور متد StopAsync برای متوقف کردن بک گراند سرویس ها وجود داره.

برای مطالعه بیشتر به قسمت منابع این پست مراجعه کنید.

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

داکیومنت مایکروسافت : https://docs.microsoft.com/en-us/dotnet/core/extensions/generic-host

سورس کد مقاله : https://github.com/softamoz/WPF.NETGenericHost