In the past, running a background task used to mean writing code to spin up a new thread. Then the Task Parallel Library came along with the async & await keywords making it easier to run tasks in the background. In ASP.NET Core 3.1 there is a new feature which makes starting services with websites even easier.
Give me the code… https://github.com/JakeDixon/background-services-with-asp-net-core
The IHostedService
interface enables you to write background tasks that can be started and stopped with the website. The interface provides two methods:StartAsync(CancellationToken stoppingToken)
andStopAsync(CancellationToken stoppingToken)
I’m going to defer to the ASP.NET Core documentation for examples of the interface because it’s well covered. https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio
What I actually want to show to you is the BackgroundService
class and how we can inherit that to simplify implementation. The BackgroundService
class implements the IHostedService
interface for us. The class also brings a new method ExecuteAsync(CancellationToken stoppingToken)
.
With the ExecuteAsync
method we don’t need to worry about the StartAsync
and StopAsync
methods. We can focus on our logic for the background task therefore keeping a cleaner code base.
Short Running Background Tasks
Tasks where you only want to run something at start up quickly can have the logic put directly into the ExecuteAsync
method and it will execute every time the website is started.
using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;
namespace BackgroundTasksASPNETCore.Services
{
public class ShortRunningSingleTaskService : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// simulate quick logic
await Task.Delay(200);
}
}
}
Long Running Background Tasks
Longer running single tasks should pay attention to the stoppingToken.IsCancellationRequested
in order to keep responsiveness high. Responding to the cancellation takes some extra consideration, like what if we were half way through cleaning a data structure… Is that a good place to exit or do we need to clean up first?
using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;
namespace BackgroundTasksASPNETCore.Services
{
public class LongRunningSingleTaskService : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// simulate logic by waiting for 2 seconds
await Task.Delay(2000);
// check if we should be exiting
if (stoppingToken.IsCancellationRequested)
{
// clean up the state before exiting
return;
}
// simulate more logic
await Task.Delay(2000);
}
}
}
Life Time Background Tasks
The last example is a life time task, this can be great for broadcasting server updates using SignalR hubs or other items that need to run constantly with the website. The life time tasks simply loop while the cancellation isn’t requested.
using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;
namespace BackgroundTasksASPNETCore.Services
{
public class LifeTimeTaskService : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while(!stoppingToken.IsCancellationRequested)
{
// do some logic, for this example lets just wait for 2 seconds
await Task.Delay(2000);
}
}
}
}
With life time tasks we also need to be cautious that they don’t contain long running logic which might affect the shutdown of the website. Again we can monitor the state of the cancellation token at appropriate points in the code… performing any clean up before exiting.
Registering The Services
The final step to remember is registering the services within ConfigureServices in the Startup class.
public void ConfigureServices(IServiceCollection services)
{
// omitted for brevity
services.AddHostedService<ShortRunningSingleTaskService>();
services.AddHostedService<LongRunningSingleTaskService>();
services.AddHostedService<LifeTimeTaskService>();
}
Conclusion
Now you’ve gained some understanding of the Background Service class and how we can use it to start and stop background services with the website.
One reply on “Background Tasks with ASP.NET Core 3.1”
Tоuche. Solid arguments. Kеep up the good spirit.