.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 처리를 한 결과는 다음 처럼 잘 동작 됩니다.
※ 전체 소스는 첨부파일로 첨부합니다.
|