ASP.NET Core is a powerful framework for building web applications, and it offers a variety of ways to run background tasks. These tasks can be anything from sending emails, processing files, performing database operations, or any other long-running operation that should not hold up your application’s main thread. In this blog post, we will explore how to run background tasks in ASP.NET Core without using any external packages.

Background tasks in web applications are essential for handling operations that are too time-consuming to be executed within a single HTTP request. ASP.NET Core provides built-in abstractions to handle these tasks elegantly and efficiently.

Using IHostedService

The IHostedService interface is a fundamental building block for running background tasks in ASP.NET Core. It provides two methods: StartAsync and StopAsync, which are called by the runtime to manage the lifetime of the service.

Creating a Background Service

Let’s create a simple background service that logs a message every minute.

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;

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

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

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _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 Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Timed Hosted Service is stopping.");

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

        return Task.CompletedTask;
    }

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

Registering the Service

To register this service, you need to add it to the dependency injection (DI) container in the ConfigureServices method in Startup.cs.

public void ConfigureServices(IServiceCollection services)
{
    services.AddHostedService<TimedHostedService>();
}

Using BackgroundService

BackgroundService is an abstract class that simplifies the implementation of a long-running IHostedService. It provides a ExecuteAsync method where you can place your background task logic.

Implementing BackgroundService

Here’s an example of how to use BackgroundService:

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;

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

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

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

        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation("Background Task Service is working.");
            await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
        }

        _logger.LogInformation("Background Task Service is stopping.");
    }
}

Registering the Background Service

Register this service in the ConfigureServices method:

public void ConfigureServices(IServiceCollection services)
{
    services.AddHostedService<BackgroundTaskService>();
}

Running Fire-and-Forget Tasks

Sometimes, you must run short-lived, fire-and-forget tasks in response to certain events. You can do this without blocking the main thread by using Task.Run.

Here’s an example of running a fire-and-forget task:

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;

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

    public IActionResult Index()
    {
        Task.Run(() => DoBackgroundWork());
        return View();
    }

    private void DoBackgroundWork()
    {
        // Simulate long-running task
        _logger.LogInformation("Fire-and-forget task started.");
        Thread.Sleep(5000);
        _logger.LogInformation("Fire-and-forget task completed.");
    }
}

Scheduled Tasks Using Timer

For more precise control over scheduled tasks, you can use the System.Threading.Timer class. This allows you to schedule tasks at fixed intervals.

Here’s an example:

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

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

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

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

        return Task.CompletedTask;
    }

    private void DoWork(object state)
    {
        _logger.LogInformation("Timed Task Service executing at {time}", DateTimeOffset.Now);
    }

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

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

        return Task.CompletedTask;
    }

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

Register this service in the ConfigureServices method.

public void ConfigureServices(IServiceCollection services)
{
    services.AddHostedService<TimedTaskService>();
}

Conclusion

Running background tasks in ASP.NET Core without any external packages is straightforward thanks to the built-in abstractions provided by the framework. Whether you need long-running tasks, fire-and-forget tasks, or scheduled tasks, ASP.NET Core has you covered with IHostedService and BackgroundService.

By leveraging these tools, you can ensure that your web applications remain responsive while performing necessary background operations. Experiment with these examples and adapt them to fit the specific needs of your application.

Categorized in:

Blog, C#, Code, Dotnet,