Condividi tramite


Implementare l'interfaccia IHostedService

Quando è necessario un controllo finito oltre l'oggetto specificato BackgroundService, è possibile implementare il proprio IHostedService. L'interfaccia IHostedService è la base per tutti i servizi a esecuzione prolungata in .NET. Le implementazioni personalizzate vengono registrate con il AddHostedService<THostedService>(IServiceCollection) metodo di estensione.

In questa esercitazione si apprenderà come:

  • Implementare le interfacce IHostedService e IAsyncDisposable.
  • Creare un servizio basato su timer.
  • Registrare l'implementazione personalizzata con inserimento e registrazione delle dipendenze.

Suggerimento

Tutto il codice sorgente di esempio "Worker in .NET" è disponibile nel browser Samples per il download. Per ulteriori informazioni, consultare Esplora esempi di codice: Worker in .NET.

Prerequisiti

Creare un nuovo progetto

Per creare un nuovo progetto del servizio di lavoro con Visual Studio, selezionare File>Nuovo progetto>. Nella finestra di dialogo Crea un nuovo progetto cercare "Servizio di lavoro" e selezionare Modello servizio di lavoro. Se si preferisce usare l'interfaccia della riga di comando di .NET, aprire il terminale preferito in una directory di lavoro. Eseguire il comando dotnet new e sostituire il <Project.Name> con il nome del progetto desiderato.

dotnet new worker --name <Project.Name>

Per ulteriori informazioni sul comando del nuovo progetto "Worker Service" della CLI di .NET, vedere dotnet new worker.

Suggerimento

Se si usa Visual Studio Code, è possibile eseguire i comandi dell'interfaccia della riga di comando di .NET dal terminale integrato. Per altre informazioni, vedere Visual Studio Code: Terminale integrato.

Creare un servizio timer

Il servizio in background basato su timer usa la System.Threading.Timer classe . Il timer attiva il DoWork metodo . Il timer viene disabilitato con IHostLifetime.StopAsync(CancellationToken) ed eliminato quando il contenitore dei servizi è eliminato con IAsyncDisposable.DisposeAsync():

Sostituire il contenuto del Worker dal modello con il codice C# seguente e rinominare il file in 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;
    }
}

Importante

Era Worker una sottoclasse di BackgroundService. Ora, TimerService implementa sia le interfacce IHostedService che IAsyncDisposable.

TimerService è sealed, e attiva la chiamata DisposeAsync dalla relativa _timer istanza. Per ulteriori informazioni sul "cascading dispose pattern", si veda come implementare un DisposeAsync metodo.

Quando StartAsync viene chiamato, il timer viene istanziato e avviato.

Suggerimento

Timer non attende il completamento delle esecuzioni precedenti di DoWork, quindi l'approccio illustrato potrebbe non essere adatto per ogni scenario. Interlocked.Increment viene usato per incrementare il contatore di esecuzione come operazione atomica, che garantisce che più thread non vengano aggiornati _executionCount contemporaneamente.

Sostituire il contenuto esistente Program con il codice C# seguente:

using App.TimerHostedService;

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

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

Il servizio viene registrato in (Program.cs) con il AddHostedService metodo di estensione. Questo è lo stesso metodo di estensione che si usa quando si registrano BackgroundService sottoclassi, poiché entrambe implementano l'interfaccia IHostedService.

Per ulteriori informazioni sulla registrazione dei servizi, vedere iniezione delle dipendenze in .NET.

Verificare la funzionalità del servizio

Per eseguire l'applicazione da Visual Studio, selezionare F5 o selezionare l'opzione di menu Debug>Avvia debug . Se usi l'interfaccia della riga di comando di .NET, esegui il comando dotnet run dalla directory di lavoro.

dotnet run

Per ulteriori informazioni sul comando di esecuzione della CLI di .NET, vedere dotnet run.

Consentire l'esecuzione dell'applicazione per un po' per generare diversi incrementi nel conteggio delle esecuzioni. Verrà visualizzato un output simile al seguente:

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.

Se si esegue l'applicazione da Visual Studio, selezionare Debug>Arresta debug.... In alternativa, selezionare CTRL + C dalla finestra della console per segnalare l'annullamento.

Vedere anche

Esistono diverse esercitazioni correlate da considerare: