ASP.NET Core 8 Web API -

Background Services

Background services in ASP.NET Core allow you to run tasks asynchronously, independent of client requests. These services can be used for various purposes such as periodic tasks, long-running operations, and handling background jobs. This guide covers how to implement and configure background services in ASP.NET Core 8 Web API, along with best practices and detailed explanations.


1. Introduction to Background Services

Background services in ASP.NET Core are implemented using hosted services. Hosted services are classes that implement the IHostedService interface and are registered with the dependency injection container.

Why Use Background Services?


2. Implementing a Background Service

To create a background service, you need to implement the IHostedService interface or derive from the BackgroundService class.

2.1 Using BackgroundService Class

The BackgroundService class is an abstract class that provides a starting point for implementing background tasks.

Example:
        
            public class TimedHostedService : BackgroundService
{
    private readonly ILogger<TimedHostedService> _logger;
    private Timer _timer;

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

    protected override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Timed Hosted Service running.");

        _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));

        return Task.CompletedTask;
    }

    private void DoWork(object state)
    {
        _logger.LogInformation("Timed Hosted Service is working.");
    }

    public override Task StopAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Timed Hosted Service is stopping.");

        _timer?.Change(Timeout.Infinite, 0);

        return base.StopAsync(stoppingToken);
    }

    public override void Dispose()
    {
        _timer?.Dispose();
        base.Dispose();
    }
}
        
    

2.2 Using IHostedService Interface

If you need more control over the hosted service, you can implement the IHostedService interface directly.

Example:
        
            public class CustomHostedService : IHostedService, IDisposable
{
    private readonly ILogger<CustomHostedService> _logger;
    private Timer _timer;

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

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Custom Hosted Service starting.");

        _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));

        return Task.CompletedTask;
    }

    private void DoWork(object state)
    {
        _logger.LogInformation("Custom Hosted Service is working.");
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Custom Hosted Service stopping.");

        _timer?.Change(Timeout.Infinite, 0);

        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }
}
        
    

3. Registering Background Services

To run background services, you need to register them with the dependency injection container.

3.1 Registering in Program.cs Example:
        
            var builder = WebApplication.CreateBuilder(args);

// Add services to the container
builder.Services.AddControllers();
builder.Services.AddHostedService<TimedHostedService>();
builder.Services.AddHostedService<CustomHostedService>();

var app = builder.Build();

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
        
    

4. Advanced Background Service Scenarios

4.1 Dependency Injection in Background Services

You can inject dependencies into your background services through the constructor.

Example:
        
            public class DependencyInjectedHostedService : BackgroundService
{
    private readonly ILogger<DependencyInjectedHostedService> _logger;
    private readonly IMyDependency _myDependency;

    public DependencyInjectedHostedService(ILogger<DependencyInjectedHostedService> logger, IMyDependency myDependency)
    {
        _logger = logger;
        _myDependency = myDependency;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Dependency Injected Hosted Service running.");

        while (!stoppingToken.IsCancellationRequested)
        {
            _myDependency.PerformTask();
            await Task.Delay(1000, stoppingToken);
        }
    }
}
        
    

4.2 Scoped Services in Background Tasks

If you need to use scoped services within a background service, create a scope manually.

Example:
        
            public class ScopedBackgroundService : BackgroundService
{
    private readonly IServiceProvider _services;
    private readonly ILogger<ScopedBackgroundService> _logger;

    public ScopedBackgroundService(IServiceProvider services, ILogger<ScopedBackgroundService> logger)
    {
        _services = services;
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Scoped Background Service running.");

        while (!stoppingToken.IsCancellationRequested)
        {
            using (var scope = _services.CreateScope())
            {
                var scopedService = scope.ServiceProvider.GetRequiredService<IMyScopedService>();
                scopedService.PerformTask();
            }

            await Task.Delay(1000, stoppingToken);
        }
    }
}
        
    

5. Periodic Tasks with Timer

Using Timer to schedule periodic tasks is a common pattern in background services.

Example:
        
            public class PeriodicTaskHostedService : IHostedService, IDisposable
{
    private readonly ILogger<PeriodicTaskHostedService> _logger;
    private Timer _timer;

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

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Periodic Task Hosted Service starting.");

        _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));

        return Task.CompletedTask;
    }

    private void DoWork(object state)
    {
        _logger.LogInformation("Periodic Task Hosted Service is working.");
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Periodic Task Hosted Service stopping.");

        _timer?.Change(Timeout.Infinite, 0);

        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }
}
        
    

6. Long-Running Background Tasks

Handling long-running tasks in a background service ensures they do not block HTTP requests.

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

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

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Long Running Task Hosted Service running.");

        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation("Long Running Task is working.");
            await Task.Delay(10000, stoppingToken); // Simulate long-running task
        }
    }
}
        
    

7. Handling Graceful Shutdown

Implementing StopAsync ensures that background services shut down gracefully.

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

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

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Graceful Shutdown Hosted Service running.");

        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation("Graceful Shutdown Task is working.");
            await Task.Delay(1000, stoppingToken);
        }
    }

    public override async Task StopAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Graceful Shutdown Hosted Service stopping.");

        await base.StopAsync(stoppingToken);
    }
}
        
    

8. Best Practices for Background Services


9. Comprehensive Example

A comprehensive example demonstrating various background services and their configurations.

Program.cs:
        
            var builder = WebApplication.CreateBuilder(args);

// Add services to the container
builder.Services.AddControllers();
builder.Services.AddScoped<IMyDependency, MyDependency>();
builder.Services.AddScoped<IMyScopedService, MyScopedService>();
builder.Services.AddHostedService<TimedHostedService>();
builder.Services.AddHostedService<CustomHostedService>();
builder.Services.AddHostedService<DependencyInjectedHostedService>();
builder.Services.AddHostedService<ScopedBackgroundService>();
builder.Services.AddHostedService<PeriodicTaskHostedService>();
builder.Services.AddHostedService<LongRunningTaskHostedService>();
builder.Services.AddHostedService<GracefulShutdownHostedService>();

var app = builder.Build();

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
        
    


Services:
        
            public interface IMyDependency
{
    void PerformTask();
}

public class MyDependency : IMyDependency
{
    public void PerformTask()
    {
        // Implementation of the task
    }
}

public interface IMyScopedService
{
    void PerformTask();
}

public class MyScopedService : IMyScopedService
{
    public void PerformTask()
    {
        // Implementation of the task
    }
}
        
    

10. Conclusion

Implementing background services in ASP.NET Core 8 Web API allows you to run tasks asynchronously, handle long-running operations, and perform periodic tasks efficiently. By following the best practices and understanding the key components and configurations, you can ensure that your background services run smoothly and reliably. This comprehensive guide provides the knowledge and tools to implement and manage background services effectively in your ASP.NET Core 8 Web API projects.