Windows フォーム アプリで .NET 汎用ホストを使用する

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

前提条件

汎用ホストを設定する

セットアップは、C# と Visual Basic の間で若干異なります。 C# で、 Program.csでホストを直接構成します。 Visual Basic では、 ApplicationEvents.vbで Application Framework のスタートアップ イベントとシャットダウン イベントを使用します。

Program.csと共にApplicationConfiguration.Initialize()でホストを構成します。

  1. ApplicationConfiguration.Initialize()を呼び出して、ビジュアル スタイル、高 DPI モード、既定のフォントなど、WinForms の既定値を構成します。
  2. CreateApplicationBuilderを使用してホストをビルドし、サービスを登録します。
  3. ホストを起動し、DI からメイン フォームを解決します。
  4. フォームを Runに渡します。
  5. フォームが閉じた後、ホストを停止して破棄します。

次のコードは、完全な Program.csを示しています。

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace HostBuilderApp;

static class Program
{
    [STAThread]
    static void Main()
    {
        ApplicationConfiguration.Initialize();

        var builder = Host.CreateApplicationBuilder();

        builder.Services.AddHostedService<SampleLifecycleService>();
        builder.Services.AddTransient<Form1>();
        builder.Services.AddSingleton<IGreetingService, GreetingService>();

        IHost host = builder.Build();

        host.Start();

        Form1 mainForm = host.Services.GetRequiredService<Form1>();
        Application.Run(mainForm);

        host.StopAsync().GetAwaiter().GetResult();
        host.Dispose();
    }
}

サービスの登録と使用

ホストを構成したら、カスタム サービスを登録し、フォームに挿入します。 サービスを作成して登録するには:

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

    public interface IGreetingService
    {
        string GetGreeting();
    }
    
    Public Interface IGreetingService
        Function GetGreeting() As String
    End Interface
    
  2. インターフェイスを実装するクラスを作成します。 GreetingService クラスは、IConfigurationからあいさつメッセージを読み取るappsettings.jsonを挿入します。

    public class GreetingService : IGreetingService
    {
        private readonly IConfiguration _configuration;
    
        public GreetingService(IConfiguration configuration)
        {
            _configuration = configuration;
        }
    
        public string GetGreeting()
        {
            return _configuration.GetValue<string>("GreetingMessage")
                ?? "Hello, World!";
        }
    }
    
    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 message Is Nothing Then
                Return "Hello, World!"
            End If
    
            Return message
        End Function
    
    End Class
    
  3. Services」セクションに示すように、ビルダーの プロパティにインターフェイスと実装を登録します。

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

汎用ホストでは、アプリケーションのライフサイクルに参加するバックグラウンド サービスを実行することもできます。 ホストの開始時と停止時にコールバックを受信する 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 プロパティのにサービスを登録します。

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

フォームでサービスを使用する

Form1は DI コンテナーから解決されるため、コンストラクターの挿入は直接機能します。

  1. フォームに必要な各サービスのコンストラクター パラメーターを追加します。
  2. 挿入されたサービスをプライベート フィールドに格納します。
  3. イベント ハンドラーまたはその他のメソッドでサービスを使用します。
public partial class Form1 : Form
{
    private readonly ILogger<Form1> _logger;
    private readonly IGreetingService _greetingService;

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

        _logger = logger;
        _greetingService = greetingService;
    }

    private void ButtonGreet_Click(object sender, EventArgs e)
    {
        string greeting = _greetingService.GetGreeting();
        lblGreeting.Text = greeting;
        _logger.LogInformation("Greeting displayed: {Greeting}", greeting);
    }
}
Public Class Form1

    Private _logger As ILogger(Of Form1)
    Private _greetingService As IGreetingService

    Sub New(ILogger As ILogger(Of Form1), greetingService As IGreetingService)
        InitializeComponent()
        _logger = ILogger
        _greetingService = greetingService
    End Sub

    Private Sub ButtonGreet_Click(sender As Object, e As EventArgs) Handles btnGreet.Click
        Dim greeting As String = _greetingService.GetGreeting()
        lblGreeting.Text = greeting
        _logger.LogInformation("Greeting displayed: {Greeting}", greeting)
    End Sub

End Class

構成を追加する

CreateApplicationBuilder appsettings.jsonを出力ディレクトリから自動的に読み込みます。 構成ファイルを追加するには:

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

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

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