Implémenter l’interface IHostedService

Lorsque vous avez besoin d’un contrôle fini au-delà du BackgroundService fourni, vous pouvez implémenter votre propre IHostedService. L’interface IHostedService est la base de tous les services de longue durée dans .NET. Les implémentations personnalisées sont inscrites auprès de la méthode d’extension AddHostedService<THostedService>(IServiceCollection).

Dans ce tutoriel, vous allez apprendre à :

  • Implémentez le IHostedService et les interfaces IAsyncDisposable.
  • Créez un service basé sur un minuteur.
  • Inscrivez l’implémentation personnalisée avec l’injection de dépendances et la journalisation.

Conseil

Tout le code source d’exemple « Workers dans .NET » peut être téléchargé dans l’Explorateur d’exemples. Pour plus d’informations, consultez Parcourir les exemples de code : Workers dans .NET.

Prérequis

Création d'un projet

Pour créer un projet de service Worker avec Visual Studio, vous devez sélectionner Fichier>Nouveau>Projet.... Dans la boîte de dialogue Créer un projet, recherchez « Worker Service », puis sélectionnez Modèle Worker Service. Si vous préférez utiliser l’interface CLI .NET, ouvrez votre terminal favori dans un répertoire de travail. Exécutez la commande dotnet new et remplacez le <Project.Name> par le nom de projet souhaité.

dotnet new worker --name <Project.Name>

Pour plus d’informations sur la commande de projet de service new worker de l’interface CLI .NET, consultez dotnet new worker.

Conseil

Si vous utilisez Visual Studio Code, vous pouvez exécuter des commandes CLI .NET à partir du terminal intégré. Pour plus d’informations, consultez Visual Studio Code : terminal intégré.

Créer un service de minuteur

Le service d’arrière-plan basé sur un minuteur utilise la classe System.Threading.Timer. Le minuteur déclenche la méthode DoWork. Le minuteur est désactivé sur IHostLifetime.StopAsync(CancellationToken) et supprimé quand le conteneur du service est supprimé sur IAsyncDisposable.DisposeAsync() :

Remplacez le contenu du modèle Worker par le code C# suivant, puis renommez le fichier en TimerService.cs :

namespace App.TimerHostedService;

public sealed class TimerService(ILogger<TimerService> logger) : IHostedService, IAsyncDisposable
{
    private readonly Task _completedTask = Task.CompletedTask;
    private int _executionCount = 0;
    private Timer? _timer;

    public Task StartAsync(CancellationToken stoppingToken)
    {
        logger.LogInformation("{Service} is running.", nameof(TimerHostedService));
        _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));

        return _completedTask;
    }

    private void DoWork(object? state)
    {
        int count = Interlocked.Increment(ref _executionCount);

        logger.LogInformation(
            "{Service} is working, execution count: {Count:#,0}",
            nameof(TimerHostedService),
            count);
    }

    public Task StopAsync(CancellationToken stoppingToken)
    {
        logger.LogInformation(
            "{Service} is stopping.", nameof(TimerHostedService));

        _timer?.Change(Timeout.Infinite, 0);

        return _completedTask;
    }

    public async ValueTask DisposeAsync()
    {
        if (_timer is IAsyncDisposable timer)
        {
            await timer.DisposeAsync();
        }

        _timer = null;
    }
}

Important

Le Worker était une sous-classe de BackgroundService. À présent, le TimerService implémente à la fois le IAsyncDisposable et les interfaces IHostedService.

Le TimerService est sealed, et passe en cascade l’appel DisposeAsync à partir de son instance _timer. Pour plus d’informations sur le « modèle de suppression en cascade », consultez Implémenter une méthode DisposeAsync.

Lorsque StartAsync est appelé, le minuteur est instancié, ce qui entraîne son démarrage.

Conseil

Le Timer n’attend pas la fin des exécutions précédentes de DoWork pour finir, de sorte que l’approche indiquée peut ne pas convenir à tous les scénarios. Interlocked.Increment est utilisé pour incrémenter le compteur d’exécution en tant qu’opération atomique, ce qui garantit que plusieurs threads ne mettent pas à jour _executionCount simultanément.

Remplacez le contenu Program existant par le code C# suivant :

using App.TimerHostedService;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<TimerService>();

IHost host = builder.Build();
host.Run();

Le service est inscrit dans (Program.cs) avec la méthode d’extension AddHostedService. Il s’agit de la même méthode d’extension que vous utilisez lors de l’inscription de sous-classes BackgroundService, car elles implémentent l’interface IHostedService.

Pour plus d’informations sur l’inscription de services, consultez Injection de dépendances dans .NET.

Vérifier les fonctionnalités du service

Pour exécuter l’application à partir de Visual Studio, sélectionnez F5 ou sélectionnez l’option de menu Déboguer>Démarrer le débogage. Si vous utilisez l’interface CLI .NET, exécutez la commande dotnet run à partir du répertoire de travail :

dotnet run

Pour plus d’informations sur la commande d’exécution de l’interface CLI .NET, consultez dotnet run.

Laissez l’application s’exécuter un peu pour générer plusieurs incréments de nombre d’exécutions. Vous devez voir des informations semblables à ce qui suit :

info: App.TimerHostedService.TimerService[0]
      TimerHostedService is running.
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: .\timer-service
info: App.TimerHostedService.TimerService[0]
      TimerHostedService is working, execution count: 1
info: App.TimerHostedService.TimerService[0]
      TimerHostedService is working, execution count: 2
info: App.TimerHostedService.TimerService[0]
      TimerHostedService is working, execution count: 3
info: App.TimerHostedService.TimerService[0]
      TimerHostedService is working, execution count: 4
info: Microsoft.Hosting.Lifetime[0]
      Application is shutting down...
info: App.TimerHostedService.TimerService[0]
      TimerHostedService is stopping.

Si vous exécutez l’application à partir de Visual Studio, sélectionnez Déboguer>Arrêter le débogage.... Vous pouvez également sélectionner Ctrl + C dans la fenêtre de console pour signaler l’annulation.

Voir aussi

Il existe plusieurs tutoriels connexes à prendre en compte :