Använda .NET Generic Host i en WPF-app

.NET Generisk Värd är ett standardiserat sätt att konfigurera och köra program med inbyggt stöd för beroendeinjektion (DI), konfiguration och loggning. WPF-program inkluderar inte Host Builder-integrering som standard, men du kan lägga till den. Den här artikeln visar hur du konfigurerar den generiska värden i en WPF-app för att integrera tjänster i dina fönster och använda den fullständiga .NET-värdinfrastrukturen.

Förutsättningar

Konfigurera den allmänna värden

Så här integrerar du Generic Host med din WPF-app:

  1. Ta bort StartupUri från programmets XAML-fil och anslut händelsehanterarna Startup och Exit.

    <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. Skapa värden i koden bakom.

    Metoden Application_Startup skapar värden med CreateApplicationBuilder, registrerar tjänster på Services egenskapen, startar värden och visar huvudfönstret:

    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. Stoppa och ta bort värden när programmet avslutas för att rensa resurser:

    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
    

Skapa en tjänst

Egenskapen Services i föregående avsnitt registrerar tjänster med DI-containern. Så här skapar du en anpassad tjänst:

  1. Definiera ett tjänstgränssnitt:

    public interface IGreetingService
    {
        string GetGreeting();
    }
    
    Public Interface IGreetingService
    
        Function GetGreeting() As String
    
    End Interface
    
  2. Skapa en klass som implementerar gränssnittet. Klassen GreetingService accepterar IConfiguration genom konstruktorinmatning för att läsa värden från 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
    

Köra en värdbaserad tjänst

Den generiska värden kan också köra bakgrundstjänster som är en del av applikationens livscykel. Värden anropar en IHostedService implementering när den startas och stoppas. Så här lägger du till en värdbaserad tjänst:

  1. Skapa en klass som implementerar IHostedService. Följande klass skriver till felsökningsutdata när värdtjänsten startar och stoppar.

    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. Registrera tjänsten med AddHostedService på byggarens Services egenskap, som du ser i Application_Startup metoden i avsnittet Konfigurera den generiska värden.

Värden kallar StartAsync när den startar och StopAsync när den stoppar, så felsökningsutdata visas i Utdatafönstret i Visual Studio.

Mata in tjänster i ett fönster

DI-containern matar in beroenden i registrerade fönster genom konstruktorinmatning. Så här använder du tjänster i ett fönster:

  1. Lägg till konstruktorparametrar för varje tjänst som fönstret behöver.
  2. Lagra de injektade tjänsterna i privata fält.
  3. Använd tjänsterna i händelsehanterare eller andra metoder.

Följande kod visar MainWindow accepterar ILogger<MainWindow> och IGreetingService genom konstruktorn:

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

Lägg till konfiguration

CreateApplicationBuilder läses appsettings.json in automatiskt när filen finns i utdatakatalogen. Så här lägger du till en konfigurationsfil i projektet:

  1. Skapa en appsettings.json fil i projektroten med dina konfigurationsvärden:

    {
      "GreetingMessage": "Hello from the .NET Generic Host!"
    }
    
  2. Ange CopyToOutputDirectory till PreserveNewest i projektfilen så att filen kopieras till utdatakatalogen:

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