Utiliser l’hôte générique .NET dans une application Windows Forms

L’hôte générique .NET offre un moyen standardisé de configurer et d’exécuter des applications avec prise en charge intégrée de l’injection de dépendances (DI), de la configuration et de la journalisation. Les applications Windows Forms n’incluent pas l’intégration de l’hôte générique par défaut, mais vous pouvez l’ajouter. Cet article explique comment configurer l’hôte générique dans une application Windows Forms pour injecter des services dans vos formulaires.

Prerequisites

Configurer l’hôte générique

La configuration diffère légèrement entre C# et Visual Basic. En C#, configurez l’hôte directement dans Program.cs. Dans Visual Basic, utilisez les événements de démarrage et d’arrêt d’Application Framework dans ApplicationEvents.vb.

Configurez l’hôte en Program.cs à côté de ApplicationConfiguration.Initialize() :

  1. Appelez ApplicationConfiguration.Initialize() pour configurer les valeurs par défaut de WinForms, notamment les styles visuels, le mode ppp élevé et les polices par défaut.
  2. Générez l’hôte avec CreateApplicationBuilder et inscrivez les services.
  3. Démarrez l’hôte et résolvez le formulaire principal à partir de l’di.
  4. Passez le formulaire à Run.
  5. Stoppez et supprimez l’hôte une fois que le formulaire est fermé.

Le code suivant montre l'intégralité du 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();
    }
}

Inscrire et consommer des services

Avec l’hôte configuré, inscrivez des services personnalisés et injectez-les dans vos formulaires. Pour créer et inscrire un service :

  1. Définissez une interface de service :

    public interface IGreetingService
    {
        string GetGreeting();
    }
    
    Public Interface IGreetingService
        Function GetGreeting() As String
    End Interface
    
  2. Créez une classe qui implémente l’interface. La GreetingService classe injecte IConfiguration pour lire le message d’accueil à partir de 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. Inscrivez l’interface et l’implémentation sur la propriété du Services générateur, comme indiqué dans la section Configurer l’hôte générique .

Exécuter un service hébergé

L’hôte générique peut également exécuter des services en arrière-plan qui participent au cycle de vie de l’application. Implémentez IHostedService pour recevoir des rappels lorsque l’hôte démarre et s’arrête. Pour ajouter un service hébergé :

  1. Créez une classe qui implémente IHostedService. La classe suivante enregistre dans la sortie de débogage lorsque l’hôte démarre et s’arrête.

    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. Inscrivez le service avec AddHostedService sur la propriété Services du générateur, comme indiqué dans la section Configurer l’hôte générique.

L’hôte appelle StartAsync au démarrage et StopAsync à l’arrêt, de sorte que la sortie du débogage s’affiche dans la fenêtre Sortie de Visual Studio.

Consommer des services dans un formulaire

Étant donné que Form1 est résolu à partir du conteneur DI, l'injection de dépendances par le constructeur fonctionne de manière directe.

  1. Ajoutez des paramètres de constructeur pour chaque service dont le formulaire a besoin.
  2. Stockez les services injectés dans des champs privés.
  3. Utilisez les services dans les gestionnaires d’événements ou d’autres méthodes.
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

Ajouter une configuration

CreateApplicationBuilder charge appsettings.json automatiquement à partir du répertoire de sortie. Pour ajouter un fichier de configuration :

  1. Créez un appsettings.json fichier à la racine du projet avec vos valeurs de configuration :

    {
      "GreetingMessage": "Hello from the Generic Host!"
    }
    
  2. Définissez CopyToOutputDirectory à PreserveNewest dans le fichier projet afin que appsettings.json soit copié dans le répertoire de sortie :

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