IHostedService y BackgroundService
Implemente IHostedService y la clase abstracta BackgroundService para ejecutar trabajo en segundo plano dentro de un host de .NET.
IHostedService y BackgroundService es una lección gratuita de C# Academy en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C# Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C# Academy incluye 4 lecciones en total.
¿Qué son los servicios en segundo plano?
Los servicios en segundo plano ejecutan tareas de larga duración junto con su aplicación ASP.NET Core: procesan colas, ejecutan tareas programadas o supervisan recursos. .NET proporciona dos interfaces: IHostedService (mínima) y la clase abstracta BackgroundService (adecuada para bucles).
Interfaz IHostedService
IHostedService tiene dos métodos: StartAsync (se llama cuando se inicia el host) y StopAsync (se llama durante el apagado ordenado). Es ideal para tareas puntuales de inicio y apagado.
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: bucles de larga duración
BackgroundService es una clase abstracta que implementa IHostedService y proporciona ExecuteAsync(CancellationToken), un método que se ejecuta durante toda la vida de la aplicación.
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>();Consumo de servicios con ámbito
Los servicios en segundo plano son Singletons. Para utilizar servicios con ámbito (como DbContext), cree siempre un ámbito nuevo por cada unidad de trabajo mediante 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);
}
}
}Apagado ordenado
Cuando el host se apaga, activa el token de cancelación. Su método ExecuteAsync debe observarlo y realizar la limpieza. De forma predeterminada, el host espera hasta 5 segundos antes de detener el proceso a la fuerza.
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();
}
}Cola en segundo plano basada en Channel
Un patrón habitual: un servicio en segundo plano lee de una cola Channel mientras los endpoints HTTP agregan elementos de trabajo. Esto desacopla el procesamiento de las solicitudes del procesamiento del trabajo.
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>();Manejo de errores en servicios en segundo plano
Las excepciones no controladas en ExecuteAsync pueden detener el servicio silenciosamente. Encierre el bucle principal en un bloque try/catch y registre los errores para mantener el servicio activo pese a los fallos individuales.
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 y tiempo de espera de apagado
Invalide StopAsync para realizar tareas de limpieza. El host proporciona un token de apagado; si la limpieza tarda más que el tiempo de espera, el proceso finaliza igualmente.
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));Varios servicios en segundo plano
Registre varios servicios hospedados; todos se ejecutan simultáneamente. El host los inicia en orden y los detiene en orden inverso.
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 shutdownCaso real: trabajador de procesamiento de pedidos
Un servicio en segundo plano que procesa pedidos pendientes de una cola de base de datos, con el uso correcto de ámbitos y el manejo adecuado de errores.
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);
}
}
}Comprobación rápida
¿Por qué deben utilizar los servicios en segundo plano IServiceScopeFactory en lugar de inyectar DbContext directamente?
Resumen: IHostedService y BackgroundService
Aspectos clave:
IHostedService: StartAsync/StopAsync — para tareas de inicio y apagadoBackgroundService: bucle ExecuteAsync — para trabajo continuo en segundo plano- Utilice siempre
IServiceScopeFactorypara las dependencias con ámbito dentro de los servicios en segundo plano - Observe el token de cancelación en cada await para permitir un apagado ordenado
- Encierre el cuerpo del bucle en un bloque try/catch para evitar que el servicio muera por errores
- Use
HostOptions.ShutdownTimeoutsi la limpieza necesita más de 5 segundos
Aprende C# con un tutor de IA — gratis
Escribe y ejecuta código real en tu navegador, obtén ayuda instantánea de un tutor de IA disponible 24/7 y continúa donde lo dejaste en la web o en la aplicación.
- Cursos
- 93
- Lecciones
- 346
Preguntas frecuentes
¿La lección «IHostedService y BackgroundService» es gratis?
Sí — el texto completo de «IHostedService y BackgroundService» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C# Academy, actualiza a CoddyKit PRO. El curso de C# Academy incluye 4 lecciones en total.
¿Qué aprenderé en «IHostedService y BackgroundService»?
Implemente IHostedService y la clase abstracta BackgroundService para ejecutar trabajo en segundo plano dentro de un host de .NET. Practicas C# Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar C# Academy?
No se requiere experiencia previa. C# Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.
¿Cuánto tiempo toma la lección «IHostedService y BackgroundService»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de C# Academy?
Sí. Cada lección de C# Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- IHostedService y BackgroundService
- Proyectos Worker Service
- Tareas periódicas y temporizadores
- Trabajos programados con Quartz.NET