내용 보기

작성자

관리자 (IP : 172.17.0.1)

날짜

2021-01-07 14:38

제목

[WPF] NET Generic Host with .NET Core 3.0


.NET Generic Host는 주로 의존성 주입, 로깅 처리 방식 패턴을 구성할 수 있는 닷넷의 확장 입니다.
ASP.NET Core에서 HostBuilder를 사용해서 Dependency injection (DI) 처리를 하는데 많이 사용했는데
이 방식은 그대로 WPF나 Winform에서 동일하게 사용 가능 합니다.

참고 : https://laurentkempe.com/2019/09/03/WPF-and-dotnet-Generic-Host-with-dotnet-Core-3-0/

이번글은 WPF에서 HostBuilder를 사용한 DI처리 방식에 대해 작성합니다.


먼저 위에서 설명했던 확장 패키지가 설치 되어 있어야 합니다.
Microsoft.Extensions.Hosting
Microsoft.Extensions.Hosting.Abstractions

위 패키지가 설치되면 HostBuilder를 사용할 수 있는데 서비스 등록을 통해 DI를 구현해 보겠습니다.


App.xaml의 기본 템플릿은 다음과 같습니다.
StartupUri속성을 제거해 수동으로 Window를 띄우도록 처리 합니다.

App.xaml
<Application x:Class="Generic_Host_WPF.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Generic_Host_WPF"
             Startup="Application_Startup"
             Exit="Application_Exit">
    <Application.Resources>
        <local:ViewModelLocator x:Key="ViewModelLocator" />
        <BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
    Application.Resources>
Application>
 
cs

ViewModelLocator를 리소스에 포함시켜 객체를 생성합니다.
그리고
Startup와 Exit의 이벤트 핸들러를 연결해 줍니다.
해당 이벤트에서 WPF응용프로그램이 실행될때 HostBuilder를 구성할 수 있도록 처리 합니다.


ViewModelLocator.cs

namespace Generic_Host_WPF
{
    using Generic_Host_WPF.Services;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using System;
 
    public class ViewModelLocator
    {
        private IHost _host;
 
        public ViewModelLocator()
        {
            _host = new HostBuilder()
                .ConfigureServices((context, services) =>
                {
                    services.AddSingleton<IDataService, DataService>();
                    services.AddTransient<MainViewModel>();
                })
                .Build();
        }
 
        public IHost Host
        {
            get => _host;
        }
 
        public MainViewModel MainViewModel
        {
            get
            {
                return _host.Services.GetService<MainViewModel>();
            }
        }
    }
}
 
cs

ViewModelLocator에서 HostBuilder를 구성하고 의존성 주입에 필요한 서비스를 등록해 줍니다.

위 코드에선 MainWindow의 ViewModel인 MainViewModel과 데이터 처리를 위한 DataService를 등록 했습니다.

프로그램 시작시 Host를 구동시켜 줄 수 있도록 IHost에 대해 읽기 전용 속성으로 노출을 시키고

각 뷰에서 접근해 사용할 수 있도록 뷰모델 속성도 노출 합니다.
이때 뷰모델의 생성은 Host가 담당하게 됨으로서 DI처리가 됩니다.


App.xaml.cs

namespace Generic_Host_WPF
{
    using Microsoft.Extensions.Hosting;
    using System;
    using System.Windows;
 
    /// 
    /// Interaction logic for App.xaml
    /// 
    public partial class App : Application
    {
        public App()
        {
            //
        }
 
        private async void Application_Startup(object sender, StartupEventArgs e)
        {
            await (App.Current.Resources["ViewModelLocator"as ViewModelLocator).Host.StartAsync();
 
            MainWindow mainWindow = new MainWindow();
            mainWindow.Show();
        }
 
        private async void Application_Exit(object sender, ExitEventArgs e)
        {
            using ((App.Current.Resources["ViewModelLocator"as ViewModelLocator).Host)
            {
                await (App.Current.Resources["ViewModelLocator"as ViewModelLocator).Host.StopAsync(TimeSpan.FromSeconds(5));
            }
        }
    }
}
 
cs

프로그램 시작시 ViewModelLocator 통해 HostBuilder가 구성되고, 구성된 Host를 구동하고

프로그램 종료시 중지시키도록 합니다.


MainWindow.xaml

<Window x:Class="Generic_Host_WPF.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"
        xmlns:local="clr-namespace:Generic_Host_WPF"
        mc:Ignorable="d"
        DataContext="{Binding MainViewModel, Source={StaticResource ViewModelLocator}}"
        Title="MainWindow" Height="450" Width="800">
cs

MainWindow에 뷰모델을 설정하고


MainViewModel.cs

public class MainViewModel : INotifyPropertyChanged
{
    private readonly IDataService _dataService;
 
    public MainViewModel(IDataService dataService)
    {
        _dataService = dataService;
    }
}
cs

다음과 같이 생성자 주입 방식을 통해 IDataService를 사용할 수 있습니다.


이렇게 .NET Generic Host - HostBuilder DI 처리를 한 결과는 다음 처럼 잘 동작 됩니다.


※ 전체 소스는 첨부파일로 첨부합니다.

출처1

https://laurentkempe.com/2019/09/03/WPF-and-dotnet-Generic-Host-with-dotnet-Core-3-0/

출처2




2022-04-05 08:06
소스 중 Spinner.png 로딩 처리 부분은 shwlee님의 https://github.com/shwlee/MVVMSample 소스를 인용하였습니다.
관리자
(172.17.0.1)