Hangfire in ASP.NET Core 8 and 10 with LiteDB

aspcore dotnet c# net8 net10 sqlite litedb

There is a working example available at the bottom of this post.

I recently rewrote my gametrakr that I made during COVID and done the rewrite in ASP.NET Core, specifically .NET 8 but this also applies to .NET 10. Two of the major reasons for the rewrite were the existing code base was a nightmare to deal with, it was never meant to be a long term solution and temporary become permanent and I didn’t have any database backups. In 2024 the VPS I was using went down and I lost everything, but just happened to have a recent export of my data for when I was trying to make a PHP MySQL > C# SQLite converter as I had planned to do the rewrite then.

When I started the rewrite the main thing I had on my mind was back ups. There’s tons of solutions out there, some free, some paid, that all work in either the same way or slightly different ways. I came across Hangfire which is a background processing library with persistent storage, free to use, and doesn’t have any requirements for Windows - which works well for me, since my entire app runs in Docker. The setup is extremely easy and with it I now have weekly (every Friday) back up jobs that get backed up to Proton Drive and sent to my email via resend.

Requirements

  • .NET Framework 4.5.1 or later (I use .NET 8 or 10)
  • Persistant Storage
  • Newtonsoft.Json >= 5.0.1
  • Hangfire >= 1.8.23
  • Hangfire.LiteDB >= 0.4.1

You can use Hangfire with loads of different storage backends, but I use LiteDB specifically as it’s low hanging and for the type of app I’m running works well. I did try to use SQLite, but the library that has been created for it just would not work, but mileage may vary.

Set up

First add Hangfire and Hangfire.LiteDB to your project using the below commands

dotnet package add Hangfire
dotnet package add Hangfire.LiteDB  

After you’ve done that, open your Program.cs and go to the section where you register your services and add Hangfire

builder.Services.AddHangfire(config =>
{
    config.UseSimpleAssemblyNameTypeSerializer()
        .UseRecommendedSerializerSettings()
        .UseLiteDbStorage("app/hangfire.db"); // You can make this whatever you want and store the string however you want, i.e appsettings.json 
});

builder.Services.AddHangfireServer();

Create a Job

I currently two jobs that run, my weekly backup and a monthly statistics share. You want to add your jobs under where you have app.UseAuthentication() and app.UseAuthorization() within your Program.cs

var jobManager = app.Services.GetRequiredService<IRecurringJobManager>();

// configure your job
jobManager.AddOrUpdate<IBackupService>(
    "weekly-db-backup",
    service => service.CreateBackup(),
    "0 6 * * 5",
    new RecurringJobOptions { TimeZone = TimeZoneInfo.FindSystemTimeZoneById("Europe/London") }
);

The above job will trigger every Friday at 6AM. IBackupService is the interface for my backup service, and service.CreateBackup() is calling the method within that implemented service. Small example below.

public interface IBackupService
{
    Task CreateBackup();
}

public class BackupService : IBackupService
{
    public async Task CreateBackup()
    {
        Console.WriteLine("Create Backup Called");
    } 
}

When you run your application you will see something similar to this in your logs/container logs

2026-06-14 17:33:53.629 +00:00 [INF] [Hangfire.BackgroundJobServer] Starting Hangfire Server using job storage: 'Connection string: /app/hangfire.db,  prefix: hangfire'
2026-06-14 17:33:53.629 +00:00 [INF] [Hangfire.BackgroundJobServer] Using the following options for LiteDB job storage:
2026-06-14 17:33:53.630 +00:00 [INF] [Hangfire.BackgroundJobServer] Using the following options for Hangfire Server:
    Worker count: 5
    Listening queues: 'default'
    Shutdown timeout: 00:00:15
    Schedule polling interval: 00:00:15
2026-06-14 17:33:53.647 +00:00 [INF] [Hangfire.Server.BackgroundServerProcess] Server 1941dffa8546:1:313e6ea6 successfully announced in 8.8561 ms
2026-06-14 17:33:53.649 +00:00 [INF] [Hangfire.Server.BackgroundServerProcess] Server 1941dffa8546:1:313e6ea6 is starting the registered dispatchers: ServerWatchdog, ServerJobCancellationWatcher, ExpirationManager, CountersAggregator, Worker, DelayedJobScheduler, RecurringJobScheduler...
2026-06-14 17:33:53.652 +00:00 [INF] [Hangfire.Server.BackgroundServerProcess] Server 1941dffa8546:1:313e6ea6 all the dispatchers started

Optional: Hangfire Dashboard

Optionally, if you want to add the Hangfire Dashboard as well you can do. By default it does not have authorization so you need to add Authorization or anyone is able to view it. I have mine configured to anyone that is logged in since it’s a One User App anyway, but you can change it obviously. As an extra layer of security mine is also behind Cloudflare One.

Add this under where you have app.UseAuthentication() and app.UseAuthorization()

app.UseHangfireDashboard("/hangfire/dashboard", new DashboardOptions
{
    Authorization = new[] { new HangfireAuthorizationFilter() }
});

For HangfireAuthorizationFilter, if you want to use mine (anyone can view as long as their authorized), you can use the below. Just create a file called HangfireAuthorizationFilter.cs and add the below into it.

using Hangfire.Annotations;
using Hangfire.Dashboard;

namespace YourApp
{
    public sealed class HangfireAuthorizationFilter : IDashboardAuthorizationFilter
    {
        public bool Authorize([NotNull] DashboardContext context)
        {
            var httpContext = context.GetHttpContext();

            // Allow all authenticated users to see the Dashboard.
            return httpContext.User.Identity?.IsAuthenticated ?? false;
        }
    }
}

You would now be able to access the dashboard at http://localhost:port/hangfire/dashboard, you can make that string whatever you want though.

Note that within the dashboard you can trigger jobs, view their run status etc. but you cannot create a new job. New jobs must be created within the code of your app.

Working example

I have created a working example and uploaded it to GitHub if you’re the type of person that learns from seeing a working implementation vs. trying to read a tutorial.

You can find that here.

If you need any help configuring or have any issues, ping me a message at webmaster @ laim.scot.