IHostedService et BackgroundService
Implémentez IHostedService et l’intergiciel abstrait BackgroundService pour exécuter des tâches en arrière-plan au sein d’un hôte .NET.
IHostedService et BackgroundService est une leçon C# Academy gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage C# Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours C# Academy comprend 4 leçons au total.
Que sont les services d’arrière-plan ?
Les services d’arrière-plan exécutent des tâches de longue durée parallèlement à votre application ASP.NET Core : traitement de files d’attente, exécution de tâches planifiées ou surveillance de ressources. .NET fournit deux abstractions : IHostedService (minimale) et la classe abstraite BackgroundService (adaptée aux boucles).
Interface IHostedService
IHostedService possède deux méthodes : StartAsync (appelée au démarrage de l’hôte) et StopAsync (appelée lors de l’arrêt progressif). Elle convient parfaitement aux tâches ponctuelles de démarrage et d’arrêt.
public class DatabaseMigratorService : IHostedService
{
private readonly IServiceScopeFactory _scopeFactory;
public DatabaseMigratorService(IServiceScopeFactory sf) => _scopeFactory = sf;
public async Task StartAsync(CancellationToken ct)
{
using var scope = _scopeFactory.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
await db.Database.MigrateAsync(ct);
}
public Task StopAsync(CancellationToken ct) => Task.CompletedTask;
}
builder.Services.AddHostedService<DatabaseMigratorService>();BackgroundService : boucles de longue durée
BackgroundService est une classe abstraite qui implémente IHostedService et fournit ExecuteAsync(CancellationToken) — une méthode qui s’exécute pendant toute la durée de vie de l’application.
public class HeartbeatService : BackgroundService
{
private readonly ILogger<HeartbeatService> _logger;
public HeartbeatService(ILogger<HeartbeatService> l) => _logger = l;
protected override async Task ExecuteAsync(CancellationToken ct)
{
_logger.LogInformation("Heartbeat service started");
while (!ct.IsCancellationRequested)
{
_logger.LogInformation("Heartbeat: {Time}", DateTime.UtcNow);
await Task.Delay(TimeSpan.FromSeconds(30), ct);
}
_logger.LogInformation("Heartbeat service stopping");
}
}
builder.Services.AddHostedService<HeartbeatService>();Utilisation de services à portée
Les services d’arrière-plan sont des singletons. Pour utiliser des services à portée (comme DbContext), créez toujours une nouvelle portée pour chaque unité de travail à l’aide de IServiceScopeFactory.
public class DataSyncService : BackgroundService
{
private readonly IServiceScopeFactory _factory;
private readonly ILogger<DataSyncService> _log;
public DataSyncService(IServiceScopeFactory f, ILogger<DataSyncService> l)
{ _factory = f; _log = l; }
protected override async Task ExecuteAsync(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
using (var scope = _factory.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
await SyncDataAsync(db, ct);
} // scope and DbContext disposed here
await Task.Delay(TimeSpan.FromMinutes(5), ct);
}
}
}Arrêt progressif
Lorsque l’hôte s’arrête, il déclenche le jeton d’annulation. Votre ExecuteAsync doit le surveiller et effectuer le nettoyage nécessaire. Par défaut, l’hôte attend jusqu’à 5 secondes avant de forcer l’arrêt.
protected override async Task ExecuteAsync(CancellationToken ct)
{
try
{
while (!ct.IsCancellationRequested)
{
await DoWorkAsync(ct);
await Task.Delay(1000, ct);
}
}
catch (OperationCanceledException)
{
// Normal shutdown — not an error
_logger.LogInformation("Service stopping due to cancellation");
}
finally
{
// Cleanup
await CleanupAsync();
}
}File d’attente d’arrière-plan fondée sur un canal
Un modèle courant consiste à ce qu’un service d’arrière-plan lise dans une file d’attente Channel tandis que les endpoint HTTP y ajoutent des éléments de travail. Cela découple le traitement des requêtes du traitement des tâches.
public class BackgroundTaskQueue
{
private readonly Channel<Func<CancellationToken, Task>> _queue
= Channel.CreateBounded<Func<CancellationToken, Task>>(100);
public ValueTask QueueAsync(Func<CancellationToken, Task> job)
=> _queue.Writer.WriteAsync(job);
public IAsyncEnumerable<Func<CancellationToken, Task>> DequeueAllAsync(
CancellationToken ct)
=> _queue.Reader.ReadAllAsync(ct);
}
// Register and use:
builder.Services.AddSingleton<BackgroundTaskQueue>();
builder.Services.AddHostedService<QueueProcessorService>();Gestion des erreurs dans les services d’arrière-plan
Des exceptions non gérées dans ExecuteAsync peuvent arrêter le service silencieusement. Entourez la boucle principale d’un bloc try/catch et journalisez les erreurs afin de maintenir le service en fonctionnement malgré les échecs individuels.
protected override async Task ExecuteAsync(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
try
{
await ProcessNextBatchAsync(ct);
}
catch (OperationCanceledException) when (ct.IsCancellationRequested)
{
break; // normal shutdown
}
catch (Exception ex)
{
_logger.LogError(ex, "Background processing error. Retrying in 5s.");
await Task.Delay(5000, ct); // backoff before retry
}
}
}StopAsync et délai d’expiration de l’arrêt
Remplacez StopAsync pour effectuer le nettoyage. L’hôte fournit un jeton d’arrêt ; si le nettoyage prend plus de temps que le délai d’expiration, le processus est tué quoi qu’il arrive.
public override async Task StopAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Service is stopping...");
// Signal internal work to stop
_internalCts.Cancel();
// Wait for the Execute loop to complete (up to timeout)
await base.StopAsync(stoppingToken);
_logger.LogInformation("Service stopped");
}
// Increase the shutdown timeout if needed:
builder.Services.Configure<HostOptions>(opt =>
opt.ShutdownTimeout = TimeSpan.FromSeconds(30));Plusieurs services d’arrière-plan
Enregistrez plusieurs services hébergés : ils s’exécutent tous simultanément. L’hôte les démarre dans l’ordre et les arrête dans l’ordre inverse.
builder.Services.AddHostedService<DatabaseMigratorService>(); // startup task
builder.Services.AddHostedService<MetricsCollectorService>(); // continuous
builder.Services.AddHostedService<EmailNotificationService>(); // continuous
builder.Services.AddHostedService<CacheWarmupService>(); // startup task
// All run concurrently after app start
// Stopped in reverse registration order on shutdownCas réel : service Worker de traitement des commandes
Un service d’arrière-plan qui traite les commandes en attente dans une file d’attente de base de données, avec une gestion correcte des portées et des erreurs.
public class OrderProcessorService : BackgroundService
{
private readonly IServiceScopeFactory _factory;
private readonly ILogger<OrderProcessorService> _log;
public OrderProcessorService(IServiceScopeFactory f, ILogger<OrderProcessorService> l)
{ _factory = f; _log = l; }
protected override async Task ExecuteAsync(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
try
{
using var scope = _factory.CreateScope();
var processor = scope.ServiceProvider.GetRequiredService<IOrderProcessor>();
int count = await processor.ProcessPendingAsync(ct);
_log.LogInformation("Processed {Count} orders", count);
}
catch (Exception ex) when (!ct.IsCancellationRequested)
{
_log.LogError(ex, "Order processing failed");
}
await Task.Delay(TimeSpan.FromSeconds(10), ct);
}
}
}Vérification rapide
Pourquoi les services d’arrière-plan doivent-ils utiliser IServiceScopeFactory au lieu d’injecter directement DbContext ?
Récapitulatif : IHostedService et BackgroundService
Points essentiels :
IHostedService: StartAsync/StopAsync — pour les tâches de démarrage et d’arrêtBackgroundService: boucle ExecuteAsync — pour les tâches d’arrière-plan continues- Utilisez toujours
IServiceScopeFactorypour les dépendances à portée dans les services d’arrière-plan - Surveillez le jeton d’annulation lors de chaque await pour permettre un arrêt progressif
- Entourez le corps de la boucle d’un bloc try/catch afin d’éviter que le service ne s’arrête en cas d’erreur
- Utilisez
HostOptions.ShutdownTimeoutsi le nettoyage nécessite plus de 5 secondes
Questions Fréquemment Posées
La leçon « IHostedService et BackgroundService » est-elle gratuite ?
Oui — le texte complet de « IHostedService et BackgroundService » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours C# Academy, passe à CoddyKit PRO. Le cours C# Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « IHostedService et BackgroundService » ?
Implémentez IHostedService et l’intergiciel abstrait BackgroundService pour exécuter des tâches en arrière-plan au sein d’un hôte .NET. Tu pratiques C# Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer C# Academy ?
Aucune expérience préalable n'est requise. C# Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.
Combien de temps prend la leçon « IHostedService et BackgroundService » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon C# Academy ?
Oui. Chaque leçon C# Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- IHostedService et BackgroundService
- Projets Worker Service
- Tâches périodiques et minuteurs
- Tâches planifiées avec Quartz.NET