How to implement background processing in ASP.Net Core

Take advantage of the IHostedService interface in ASP.Net Core to build and run background tasks or hosted services

How to implement background processing in ASP.Net Core
Thinkstock

When developing web applications, you will often need to schedule and run background tasks. The IHostedService interface in ASP.Net Core provides a simple way to implement services that execute in the background. In this post we will explore how we can use this interface to implement background tasks, aka “hosted services,” in ASP.Net Core.

The IHostedService interface was introduced in ASP.Net Core 2.0. Here is a look at this interface.

public interface IHostedService
{
    //
    // Summary:
    //     Triggered when the application host is ready to start the service.
    Task StartAsync(CancellationToken cancellationToken);
    //
    // Summary:
    //     Triggered when the application host is performing a graceful shutdown.
    Task StopAsync(CancellationToken cancellationToken);
}

Implement the IHostedService interface 

When implementing the IHostedService interface, we will have to implement two methods in our code. These include the StartAsync() and StopAsync() methods; the former is called at startup, the latter is called at shutdown. Note that the implementations will vary depending on the background processing we want to execute.

In this example, we will take advantage of the following abstract base class created by Microsoft’s David Fowler.

public abstract class HostedService : IHostedService
    {
        private Task _executingTask;
        private CancellationTokenSource _cts;
        public Task StartAsync(CancellationToken cancellationToken)
        {
            // Create a linked token so we can trigger cancellation outside of this token’s cancellation
            _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
            // Store the task we’re executing
            _executingTask = ExecuteAsync(_cts.Token);
            // If the task is completed then return it
            if (_executingTask.IsCompleted)
            {
                return _executingTask;
            }
            // Otherwise it’s running
            return Task.CompletedTask;
        }
        public async Task StopAsync(CancellationToken cancellationToken)
        {
            // Stop called without start
            if (_executingTask == null)
            {
                return;
            }
            // Signal cancellation to the executing method
            _cts.Cancel();
            // Wait until the task completes or the stop token triggers
            await Task.WhenAny(_executingTask, Task.Delay(-1, cancellationToken));
            // Throw if cancellation triggered
            cancellationToken.ThrowIfCancellationRequested();
        }
        // Derived classes should override this and execute a long running method until
        // cancellation is requested
        protected abstract Task ExecuteAsync(CancellationToken cancellationToken);
    }

Extend the base class and implement ExecuteAsync

Now that this base class is available, all we need to do is extend this class and implement the ExecuteAsync method. Let’s do that by creating our own IDGBackgroundService class, shown in the code snippet below.

public class IDGBackgroundService : HostedService
{
    protected override async Task ExecuteAsync(CancellationToken cancellationToken)
    {
        //Write your custom implementation here
    }
}

Our IDGBackgroundService will read data from an external data source every 60 seconds and update a log file accordingly. Of course you could make this duration configurable, or write your own custom implementation for the service. Below is the updated version of the IDGBackgroundService class that illustrates how the ExecuteAsync method is implemented. Note that the ExecuteAsync method accepts a cancellation token as a parameter.

public class IDGBackgroundService  : HostedService
{
    private readonly IDGDataProvider _dataProvider;
    public DataRefreshService(IDGDataProvider dataProvider)
    {
        _dataProvider = dataProvider;
    }
    protected override async Task ExecuteAsync(CancellationToken cancellationToken)
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            await _dataProvider.UpdateLogFile(cancellationToken);
            await Task.Delay(TimeSpan.FromSeconds(60), cancellationToken);
        }
    }
}

As you see in the code snippet above, the IDGDataProvider class reads data from an external data source and then stores the data retrieved in a log file. Below you can see what this class would look like. I will leave the implementation blank here, but you can take a look at my article on building a custom logger.

public class IDGDataProvider
{
    public async Task UpdateLogFile(CancellationToken cancellationToken)
    {
        //Write your own implementation here
    }
   //Other members
}

Wire up our service classes with dependency injection

Lastly, we should wire up our service using dependency injection so that it will start automatically when our application is started. To do this, we will need to add the service in the ConfigureServices method of the Startup class as shown below.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddSingleton<IDGDataProvider>();
    services.AddSingleton<IHostedService, IDGBackgroundService>();
}

The IHostedService interface in ASP.Net Core provides a nice and simple way to implement background tasks in a web application. Any hosted services that you will build by implementing this interface should be registered at startup using dependency injection. You can take advantage of the IHostedService interface to spin up multiple tasks while at the same time ensuring that such tasks will shut down gracefully whenever the web host shuts down.

Copyright © 2018 IDG Communications, Inc.