Usare i servizi con ambito all'interno di una classe BackgroundService
Quando si registrano implementazioni di IHostedService usando uno dei metodi di estensione AddHostedService, il servizio viene registrato come singleton. Potrebbero esserci scenari in cui si vuole fare affidamento su un servizio con ambito. Per altre informazioni, vedere Inserimento delle dipendenze in .NET: durate dei servizi.
In questa esercitazione apprenderai a:
- Risolvere le dipendenze con ambito in un singleton BackgroundService.
- Delegare il lavoro a un servizio con ambito.
- Implementare un
override
di BackgroundService.StopAsync(CancellationToken).
Suggerimento
Tutto il codice sorgente di esempio di "Servizi ruolo di lavoro in .NET" è disponibile per il download in Esplorazione esempi. Per altre informazioni, vedere Esplorare esempi di codice: Servizi ruolo di lavoro in .NET.
Prerequisiti
- .NET 8.0 SDK o versioni successive
- Ambiente di sviluppo integrato .NET (IDE)
- È possibile usare Visual Studio
Crea un nuovo progetto
Per creare un nuovo progetto del servizio ruolo di lavoro con Visual Studio, selezionare File>Nuovo>Progetto.... Nella finestra di dialogo Crea un nuovo progetto cercare "Servizio del ruolo di lavoro" e selezionare Modello del servizio ruolo 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 altre informazioni sul comando new worker service project dell'interfaccia della riga di comando 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 servizi con ambito
Per usare i servizi con ambito all'interno di BackgroundService
, creare un ambito. Non viene creato automaticamente alcun ambito per un servizio ospitato. Il servizio in background con ambito contiene la logica dell'attività in background.
namespace App.ScopedService;
public interface IScopedProcessingService
{
Task DoWorkAsync(CancellationToken stoppingToken);
}
L'interfaccia precedente definisce un singolo metodo DoWorkAsync
. Per definire l'implementazione predefinita:
- Il servizio è asincrono. Il metodo
DoWorkAsync
restituisce un oggettoTask
. Ai fini della dimostrazione, un ritardo di dieci secondi è atteso nel metodoDoWorkAsync
. - Un'interfaccia ILogger viene inserita nel servizio:
namespace App.ScopedService;
public sealed class DefaultScopedProcessingService(
ILogger<DefaultScopedProcessingService> logger) : IScopedProcessingService
{
private int _executionCount;
public async Task DoWorkAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
++ _executionCount;
logger.LogInformation(
"{ServiceName} working, execution count: {Count}",
nameof(DefaultScopedProcessingService),
_executionCount);
await Task.Delay(10_000, stoppingToken);
}
}
}
Il servizio ospitato crea un ambito per risolvere il servizio in background con ambito e chiamare il relativo metodo DoWorkAsync
. DoWorkAsync
restituisce un Task
, atteso in ExecuteAsync
:
Riscrivere la classe Worker
Sostituire la classe Worker
esistente con il codice C# seguente e rinominare il file in ScopedBackgroundService.cs:
namespace App.ScopedService;
public sealed class ScopedBackgroundService(
IServiceScopeFactory serviceScopeFactory,
ILogger<ScopedBackgroundService> logger) : BackgroundService
{
private const string ClassName = nameof(ScopedBackgroundService);
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
logger.LogInformation(
"{Name} is running.", ClassName);
await DoWorkAsync(stoppingToken);
}
private async Task DoWorkAsync(CancellationToken stoppingToken)
{
logger.LogInformation(
"{Name} is working.", ClassName);
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
IScopedProcessingService scopedProcessingService =
scope.ServiceProvider.GetRequiredService<IScopedProcessingService>();
await scopedProcessingService.DoWorkAsync(stoppingToken);
}
}
public override async Task StopAsync(CancellationToken stoppingToken)
{
logger.LogInformation(
"{Name} is stopping.", ClassName);
await base.StopAsync(stoppingToken);
}
}
Nel codice precedente viene creato un ambito esplicito e l'implementazione IScopedProcessingService
viene risolta dalla factory dell'ambito del servizio di inserimento delle dipendenze. L'istanza del servizio risolta è con ambito e il relativo metodo DoWorkAsync
è atteso.
Sostituire i contenuti del file Program.cs del modello con il codice C# seguente:
using App.ScopedService;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<ScopedBackgroundService>();
builder.Services.AddScoped<IScopedProcessingService, DefaultScopedProcessingService>();
IHost host = builder.Build();
host.Run();
I servizi vengono registrati in (Program.cs). Il servizio ospitato viene registrato con il metodo di estensione AddHostedService
.
Per altre informazioni sulla registrazione dei servizi, vedere Inserimento delle dipendenze in .NET.
Verificare la funzionalità del servizio
Per eseguire l'applicazione da Visual Studio, selezionare F5 oppure selezionare l'opzione di menu Debug>Avvia debug. Se si usa l'interfaccia della riga di comando di .NET, eseguire il comando dotnet run
dalla directory di lavoro:
dotnet run
Per altre informazioni sul comando run dell'interfaccia della riga di comando di .NET, vedere dotnet run.
Consentire l'esecuzione dell'applicazione per qualche minuto per generare diversi incrementi del numero di esecuzioni. L'output sarà simile al seguente:
info: App.ScopedService.ScopedBackgroundService[0]
ScopedBackgroundService is running.
info: App.ScopedService.ScopedBackgroundService[0]
ScopedBackgroundService is working.
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService working, execution count: 1
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: .\scoped-service
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService working, execution count: 2
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService working, execution count: 3
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService working, execution count: 4
info: Microsoft.Hosting.Lifetime[0]
Application is shutting down...
info: App.ScopedService.ScopedBackgroundService[0]
ScopedBackgroundService 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.