IHostedService e BackgroundService
Implemente IHostedService e o BackgroundService abstrato para executar trabalho em segundo plano dentro de um host .NET.
IHostedService e BackgroundService é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C# Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C# Academy inclui 4 aulas no total.
O que são serviços em segundo plano
Os serviços em segundo plano executam trabalhos de longa duração junto com seu aplicativo ASP.NET Core — processando filas, executando tarefas agendadas ou monitorando recursos. O .NET fornece duas interfaces: IHostedService (mínima) e a classe abstrata BackgroundService (adequada para loops).
Interface IHostedService
IHostedService tem dois métodos: StartAsync (chamado quando o hospedeiro é iniciado) e StopAsync (chamado durante o desligamento ordenado). É ideal para tarefas de inicialização e desligamento executadas uma única vez.
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: loops de longa duração
BackgroundService é uma classe abstrata que implementa IHostedService e fornece ExecuteAsync(CancellationToken) — um método executado durante todo o ciclo de vida do aplicativo.
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>();Consumindo serviços com escopo
Os serviços em segundo plano são Singletons. Para usar serviços com escopo (como DbContext), sempre crie um novo escopo por unidade de trabalho usando 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);
}
}
}Desligamento ordenado
Quando o hospedeiro é desligado, ele dispara o token de cancelamento. Seu ExecuteAsync deve observá-lo e fazer a limpeza. O hospedeiro aguarda até 5 segundos (o padrão) antes de forçar a parada.
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();
}
}Fila em segundo plano baseada em canal
Um padrão comum: o serviço em segundo plano lê de uma fila de canal enquanto os pontos de extremidade HTTP enfileiram itens de trabalho. Isso desacopla o tratamento das solicitações do processamento do trabalho.
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>();Tratamento de erros em serviços em segundo plano
Exceções não tratadas em ExecuteAsync podem interromper o serviço silenciosamente. Envolva o loop principal em try/catch e registre os erros para manter o serviço ativo apesar de falhas individuais.
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 e tempo limite de desligamento
Substitua StopAsync para realizar a limpeza. O hospedeiro fornece um token de desligamento — se a limpeza demorar mais que o tempo limite, o processo será encerrado independentemente disso.
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));Vários serviços em segundo plano
Registre vários serviços hospedados — todos são executados simultaneamente. O hospedeiro os inicia na ordem e os interrompe na ordem inversa.
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 shutdownExemplo real: trabalhador de processamento de pedidos
Um serviço em segundo plano que processa pedidos pendentes de uma fila do banco de dados, com escopo e tratamento de erros adequados.
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);
}
}
}Verificação rápida
Por que os serviços em segundo plano devem usar IServiceScopeFactory em vez de injetar DbContext diretamente?
Recapitulação: IHostedService e BackgroundService
Principais conclusões:
IHostedService: StartAsync/StopAsync — para tarefas de inicialização e desligamentoBackgroundService: loop ExecuteAsync — para trabalho contínuo em segundo plano- Sempre use
IServiceScopeFactorypara dependências com escopo dentro de serviços em segundo plano - Observe o token de cancelamento em cada await para um desligamento ordenado
- Envolva o corpo do loop em try/catch para evitar que o serviço seja encerrado devido a erros
- Use
HostOptions.ShutdownTimeoutse a limpeza precisar de mais de 5 segundos
Aprenda C# com um tutor de IA — grátis
Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.
- Cursos
- 93
- Aulas
- 346
Perguntas Frequentes
A aula “IHostedService e BackgroundService” é grátis?
Sim — o texto completo de “IHostedService e BackgroundService” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C# Academy, atualize para CoddyKit PRO. O curso de C# Academy inclui 4 aulas no total.
O que vou aprender em “IHostedService e BackgroundService”?
Implemente IHostedService e o BackgroundService abstrato para executar trabalho em segundo plano dentro de um host .NET. Você pratica C# Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar C# Academy?
Nenhuma experiência prévia é necessária. C# Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.
Quanto tempo leva a aula “IHostedService e BackgroundService”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de C# Academy?
Sim. Cada aula de C# Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- IHostedService e BackgroundService
- Projetos de Worker Service
- Tarefas periódicas e temporizadores
- Trabalhos agendados com Quartz.NET