WPF アプリで .NET 汎用ホストを使用する

.NET 汎用ホストは、依存関係の挿入 (DI)、構成、およびログ記録の組み込みサポートを使用してアプリケーションを構成および実行するための標準化された方法を提供します。 WPF アプリケーションには既定では Host Builder 統合は含まれませんが、追加することはできます。 この記事では、WPF アプリで汎用ホストを設定して、サービスをウィンドウに挿入し、完全な .NET ホスティング インフラストラクチャを使用する方法について説明します。

前提条件

汎用ホストを設定する

汎用ホストを WPF アプリと統合するには:

  1. アプリケーション XAML ファイルから StartupUri を削除し、 StartupExit イベント ハンドラーを接続します。

    <Application x:Class="HostBuilderApp.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 Startup="Application_Startup"
                 Exit="Application_Exit">
        <Application.Resources>
        </Application.Resources>
    </Application>
    
  2. コードビハインドでホストをビルドします。

    Application_Startup メソッドは、CreateApplicationBuilderを使用してホストを作成し、Services プロパティにサービスを登録し、ホストを開始して、メイン ウィンドウを表示します。

    private async void Application_Startup(object sender, StartupEventArgs e)
    {
        var builder = Host.CreateApplicationBuilder();
    
        builder.Services.AddHostedService<SampleLifecycleService>();
        builder.Services.AddSingleton<IGreetingService, GreetingService>();
        builder.Services.AddSingleton<MainWindow>();
    
        _host = builder.Build();
    
        await _host.StartAsync();
    
        MainWindow mainWindow = _host.Services.GetRequiredService<MainWindow>();
        mainWindow.Show();
    }
    
    Private Async Sub Application_Startup(sender As Object, e As StartupEventArgs)
        Dim builder = Host.CreateApplicationBuilder()
    
        builder.Services.AddHostedService(Of SampleLifecycleService)()
        builder.Services.AddSingleton(Of IGreetingService, GreetingService)()
        builder.Services.AddSingleton(Of MainWindow)()
    
        _host = builder.Build()
    
        Await _host.StartAsync()
    
        Dim mainWindow As MainWindow = _host.Services.GetRequiredService(Of MainWindow)()
        mainWindow.Show()
    End Sub
    
  3. アプリケーションが終了してリソースをクリーンアップするときに、ホストを停止して破棄します。

    private async void Application_Exit(object sender, ExitEventArgs e)
    {
        using (_host)
        {
            await _host.StopAsync();
        }
    }
    
    Private Async Sub Application_Exit(sender As Object, e As ExitEventArgs)
        Using _host
            Await _host.StopAsync()
        End Using
    End Sub
    

サービスを作成する

前のセクションの Services プロパティは、サービスを DI コンテナーに登録します。 カスタム サービスを作成するには:

  1. サービス インターフェイスを定義します。

    public interface IGreetingService
    {
        string GetGreeting();
    }
    
    Public Interface IGreetingService
    
        Function GetGreeting() As String
    
    End Interface
    
  2. インターフェイスを実装するクラスを作成します。 GreetingService クラスは、IConfigurationから値を読み取るためにコンストラクターの挿入によってappsettings.jsonを受け入れます。

    public class GreetingService(IConfiguration configuration) : IGreetingService
    {
        public string GetGreeting() =>
            configuration.GetValue<string>("GreetingMessage")
            ?? "Hello from the Generic Host!";
    }
    
    Public Class GreetingService
        Implements IGreetingService
    
        Private ReadOnly _configuration As IConfiguration
    
        Public Sub New(configuration As IConfiguration)
            _configuration = configuration
        End Sub
    
        Public Function GetGreeting() As String Implements IGreetingService.GetGreeting
            Dim message As String = _configuration.GetValue(Of String)("GreetingMessage")
    
            If String.IsNullOrEmpty(message) Then
                Return "Hello from the Generic Host!"
            End If
    
            Return message
        End Function
    
    End Class
    

ホステッド サービスを実行する

汎用ホストでは、アプリケーションのライフサイクルに参加するバックグラウンド サービスを実行することもできます。 ホストは、開始と停止時に IHostedService 実装を呼び出します。 ホステッド サービスを追加するには:

  1. IHostedService を実装するクラスを作成します。 次のクラスは、ホストの起動時と停止時にデバッグ出力に書き込みます。

    public class SampleLifecycleService : IHostedService
    {
        public Task StartAsync(CancellationToken cancellationToken)
        {
            System.Diagnostics.Debug.WriteLine("SampleLifecycleService: Started.");
            return Task.CompletedTask;
        }
    
        public Task StopAsync(CancellationToken cancellationToken)
        {
            System.Diagnostics.Debug.WriteLine("SampleLifecycleService: Stopped.");
            return Task.CompletedTask;
        }
    }
    
    Public Class SampleLifecycleService
        Implements IHostedService
    
        Public Function StartAsync(cancellationToken As CancellationToken) As Task Implements IHostedService.StartAsync
            System.Diagnostics.Debug.WriteLine("SampleLifecycleService: Started.")
            Return Task.CompletedTask
        End Function
    
        Public Function StopAsync(cancellationToken As CancellationToken) As Task Implements IHostedService.StopAsync
            System.Diagnostics.Debug.WriteLine("SampleLifecycleService: Stopped.")
            Return Task.CompletedTask
        End Function
    
    End Class
    
  2. AddHostedService」セクションの「Servicesメソッド」に示すように、ビルダーのApplication_Startup プロパティにサービスを登録します。

ホストは起動時に StartAsync を呼び出し、停止すると StopAsync するため、Visual Studio の [出力 ] ウィンドウにデバッグ出力が表示されます。

ウィンドウにサービスを挿入する

DI コンテナーは、コンストラクターの挿入を通じて、登録済みのウィンドウに依存関係を挿入します。 ウィンドウでサービスを使用するには:

  1. ウィンドウに必要な各サービスのコンストラクター パラメーターを追加します。
  2. 挿入されたサービスをプライベート フィールドに格納します。
  3. イベント ハンドラーまたはその他のメソッドでサービスを使用します。

次のコードは、コンストラクターを介してMainWindowILogger<MainWindow>を受け入れるIGreetingServiceを示しています。

public partial class MainWindow : Window
{
    private readonly ILogger<MainWindow> _logger;
    private readonly IGreetingService _greetingService;

    public MainWindow(ILogger<MainWindow> logger, IGreetingService greetingService)
    {
        InitializeComponent();

        _logger = logger;
        _greetingService = greetingService;
    }

    private void OnGetGreetingClick(object sender, RoutedEventArgs e)
    {
        _logger.LogInformation("Get Greeting button clicked.");
        GreetingText.Text = _greetingService.GetGreeting();
    }
}
Class MainWindow

    Private ReadOnly _logger As ILogger(Of MainWindow)
    Private ReadOnly _greetingService As IGreetingService

    Public Sub New(logger As ILogger(Of MainWindow), greetingService As IGreetingService)
        InitializeComponent()

        _logger = logger
        _greetingService = greetingService
    End Sub

    Private Sub OnGetGreetingClick(sender As Object, e As RoutedEventArgs)
        _logger.LogInformation("Get Greeting button clicked.")
        GreetingText.Text = _greetingService.GetGreeting()
    End Sub

End Class

構成を追加する

CreateApplicationBuilder は、ファイルが出力ディレクトリにあるときに appsettings.json を自動的に読み込みます。 構成ファイルをプロジェクトに追加するには:

  1. 構成値を使用して、プロジェクト ルートに appsettings.json ファイルを作成します。

    {
      "GreetingMessage": "Hello from the .NET Generic Host!"
    }
    
  2. CopyToOutputDirectoryをプロジェクト ファイルでPreserveNewestに設定して、ファイルが出力ディレクトリにコピーされるようにします。

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>net10.0-windows</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
        <UseWPF>true</UseWPF>
      </PropertyGroup>
    
      <ItemGroup>
        <None Update="appsettings.json">
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
      </ItemGroup>
    
      <ItemGroup>
        <PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.*" />
      </ItemGroup>
    
    </Project>