Course contentsShow
← C#
Lesson 1518 of 1,90814. Background Work and MessagingFree lesson

Implementing BackgroundService Base Class

Create robust long-running background tasks using the simplified .NET worker template.

In this lesson, you will learn how to simplify the creation of long-running background tasks by leveraging the BackgroundService base class instead of implementing IHostedService manually.

Moving Beyond IHostedService

While IHostedService provides the raw foundation for background work, it requires you to manage the entire lifecycle manually—including thread safety and ensuring your service stops gracefully when the application shuts down. The BackgroundService class acts as a template, abstracting away the complex plumbing so you can focus on your actual business logic.

Implementing the Base Class

To use it, you simply inherit from BackgroundService and override the ExecuteAsync(CancellationToken stoppingToken) method. The runtime manages the startup and shutdown sequence for you, automatically passing in a stoppingToken that signals when the host is ready to terminate.

Here is how you implement a simple worker that performs a recurring task:

public class PeriodicTaskWorker : BackgroundService
{
    private readonly ILogger<PeriodicTaskWorker> _logger;

    public PeriodicTaskWorker(ILogger<PeriodicTaskWorker> logger)
    {
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // Execute loop while the application is running
        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
            
            // Perform background work
            await DoWorkAsync();

            // Wait for a period without blocking thread pool threads
            await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
        }
    }
}

Why this is robust

  1. Graceful Shutdown: By observing the stoppingToken in your Task.Delay and your logic, the service reacts immediately to application shutdown requests, preventing incomplete operations.
  2. Simplified Lifecycle: You no longer need to worry about StartAsync or StopAsync boilerplate; the base class handles the Task return types and task management automatically.
  3. Readability: Your background logic remains isolated within a single, predictable loop, making it significantly easier to maintain compared to manually managing task states in a custom IHostedService implementation.

Key Takeaway: Inheriting from BackgroundService allows you to focus purely on your execution logic while gaining built-in, robust handling of the application lifecycle and cancellation signals.