Back to all posts

Implementing Background Tasks in ASP.NET Core with HangFire

Posted on Nov 14, 2018

Posted in category:
Development
ASP.NET

Background job processing can be incredibly helpful. Anything from kicking off a longer-running process, to regular process of things such as outbound emails, and everything in-between. There are many methods or tools to be able to do this, however, finding an accurate getting started guide that works for a full implementation in ASP.NET Core is hard. In this post we will work through adding support for background tasks in ASP.NET Core using HangFire.

The Goal

By following the steps in this guide we want to accomplish the following goals:

  • Install needed packages for HangFire
  • Configure HangFire to run inside our ASP.NET Core Application
  • Ensure that only administrator users can view HangFire Server admin
  • Trigger a simple job, using dependency injection

This should cover most basic scenarios.

Initial Setup

For clarity, I am going to break the set up into two sections; initial configuration and security. This will allow us to focus on the key elements & differences along the way.

Install NuGet Package

This is one of the first areas of confusion when looking at the documentation. You only need to install the main HangFire package. Behind the scenes, it will automatically install the core package, support for ASP.NET Core, and SqlServer storage. You can do this with the following command.

Install-Package HangFire

Modify Startup.cs ConfigureServices()

Now we need to configure HangFire as a service in our application, you can do this using the following snippet, this is assuming usage of DefaultConnection as the name of your application connection string.

services.AddHangfire(x =>
x.UseSqlServerStorage(
	Configuration.GetConnectionString("DefaultConnection")));

You should place this inside the ConfigureServices() method, and I prefer to place it at the end, to ensure all other items get precedent.

You can utilize your existing database with no impact to Migrations or you can create a separate database to store the HangFire data.

Modify Startup.cs Configure()

Now that we have registered HangFire as a service, we need to actually start it up. We want to start both the HangFire server as well as the dashboard component. For this we add the following two lines to our startup.cs' Configure() method.

app.UseHangfireServer();
app.UseHangfireDashboard("/hangfire");

Queue A Sample Job

Just to make sure that everything is working, add one additional line to your Configure() code to perform a task. For the purposes of this example just use a Console.WritelIne such as the following.

BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget!"));

Build & Test

To make sure that your basic configuration is working run your application, once it is started try navigaging to /hangfire. You should see the hangfire dashboard, and 1 job listed, most likely in the "Completed" status. At this point you have things working, but the dashboard will only work locally.

Extending the Implementation for Security

Being secured to local requests by default is nice, however, for many of us that does no good! We can easily extend HangFire with our own custom authorization configuration to secure our application. It is important to note that there are references to HangFire.Dashboard.Authorization package, however, it does not have any implementations for .NET core projects.

Create an Authorization Filter

You will need to create your own implementation of the HangFire IDashboardAuthorizationFilter within your project. I will call mine HangFireAuthorization and a snippet is below.

public class HangFireAuthorization : IDashboardAuthorizationFilter
{
    private readonly IAuthorizationService _authorizationService;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public HangFireAuthorization(IAuthorizationService authorizationService,
        IHttpContextAccessor httpContextAccessor)
    {
        _authorizationService = authorizationService;
        _httpContextAccessor = httpContextAccessor;
    }

    public bool Authorize([NotNull] DashboardContext context)
    {
        return true;// Do your stuff here
    }
}

In this implementation you will want to do whatever logic is necessary in the Authorize method to validate that the user has access. This could be as simple as checking to see that they are logged in, or really anything you desire. Once this is completed we can simply wire this into the startup code.

Modify Startup.cs Configure() Code

We will replace our existing two-line configuration with the following, I've purposefully left this using the long-form implementation to keep things simple. You can use dependency injection to register your implementation and simplify this declaration if desired.

var hangFireAuth = new DashboardOptions
{
    Authorization = new[]
    {
        new HangFireAuthorization(app.ApplicationServices.GetService<iauthorizationservice>(),
            app.ApplicationServices.GetService<ihttpcontextaccessor>())
    }
};
app.UseHangfireServer();
app.UseHangfireDashboard("/hangfire", options: hangfireAuth);

If you run your application again, your security rules should be applied, and the application will deny other requests submitted.

Conclusion

It is simple to get a system such as HangFire up and running. The complication comes when these platforms grow and add support for .NET Core the documentation isn't always great. With this all setup you can use the documentation to discover other job task creation. Hope this helps!