Verwenden des generischen .NET-Hosts in einer Windows Forms-App

Der .NET Generic Host bietet eine standardisierte Möglichkeit zum Konfigurieren und Ausführen von Anwendungen mit integrierter Unterstützung für Abhängigkeitsinjektion (Dependency Injection, DI), Konfiguration und Protokollierung. Windows Forms-Apps enthalten standardmäßig keine generische Hostintegration, aber Sie können sie hinzufügen. In diesem Artikel wird gezeigt, wie Sie den generischen Host in einer Windows Forms-App einrichten, um Dienste in Ihre Formulare einzufügen.

Voraussetzungen

Einrichten des generischen Hosts

Das Setup unterscheidet sich geringfügig zwischen C# und Visual Basic. Konfigurieren Sie in C# den Host direkt in Program.cs. Verwenden Sie in Visual Basic die Start- und Beenden-Ereignisse des Anwendungs-Frameworks in ApplicationEvents.vb.

Richten Sie den Host Program.cs gemeinsam mit ApplicationConfiguration.Initialize() ein.

  1. Aufruf ApplicationConfiguration.Initialize() zum Konfigurieren von WinForms-Standardwerten, einschließlich visueller Stile, hoher DPI-Modus und Standardschriftarten.
  2. Erstellen Sie den Host mit CreateApplicationBuilder und registrieren Sie Dienste.
  3. Starten Sie den Host, und lösen Sie das Hauptformular aus DI auf.
  4. Übergeben Sie das Formular an Run.
  5. Beenden und löschen Sie den Host, nachdem das Formular geschlossen wurde.

Der folgende Code zeigt den vollständigen Program.csCode:

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();
    }
}

Registrieren und Nutzen von Diensten

Registrieren Sie beim konfigurierten Host benutzerdefinierte Dienste, und fügen Sie sie in Ihre Formulare ein. So erstellen und registrieren Sie einen Dienst:

  1. Definieren einer Dienstschnittstelle:

    public interface IGreetingService
    {
        string GetGreeting();
    }
    
    Public Interface IGreetingService
        Function GetGreeting() As String
    End Interface
    
  2. Erstellen Sie eine Klasse, die die Schnittstelle implementiert. Die GreetingService Klasse injiziert IConfiguration, um die Begrüßungsnachricht von appsettings.json zu lesen:

    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. Registrieren Sie die Schnittstelle und Implementierung in der Eigenschaft des Builders Services, wie im Abschnitt Generic Host einrichten gezeigt.

Ausführen eines gehosteten Diensts

Der generische Host kann auch Hintergrunddienste ausführen, die am Anwendungslebenszyklus teilnehmen. Implementieren Sie IHostedService, um Rückrufe zu empfangen, wenn der Host startet und stoppt. So fügen Sie einen gehosteten Dienst hinzu:

  1. Erstellen Sie eine Klasse, die das IHostedService implementiert. Die folgende Klasse schreibt in die Debugausgabe, sobald der Host gestartet wird und endet.

    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. Registrieren Sie den Dienst bei AddHostedService in der Eigenschaft Services des Builders, wie im Abschnitt Generic Host einrichten gezeigt.

Der Host ruft StartAsync beim Starten und StopAsync beim Herunterfahren auf, sodass die Debugausgabe im Ausgabefenster in Visual Studio angezeigt wird.

Nutzen von Diensten in einem Formular

Da Form1 aus dem DI-Container aufgelöst wird, funktioniert die Konstruktoreinfügung direkt:

  1. Fügen Sie Konstruktorparameter für jeden Dienst hinzu, den das Formular benötigt.
  2. Speichern Sie die eingefügten Dienste in privaten Feldern.
  3. Verwenden Sie die Dienste in Ereignishandlern oder anderen Methoden.
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

Hinzufügen einer Konfiguration

CreateApplicationBuilder lädt appsettings.json automatisch aus dem Ausgabeverzeichnis. So fügen Sie eine Konfigurationsdatei hinzu:

  1. Erstellen Sie eine appsettings.json Datei im Projektstamm mit Ihren Konfigurationswerten:

    {
      "GreetingMessage": "Hello from the Generic Host!"
    }
    
  2. Setzen Sie CopyToOutputDirectory auf PreserveNewest in der Projektdatei, damit appsettings.json in das Ausgabeverzeichnis kopiert wird.

    <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>