Loading...

BackgroundJob (Hangfire) with .NET


This blog post introduces Hangfire, a powerful and reliable library used for managing background tasks in .NET applications. Hangfire allows long-running or periodic operations such as sending emails, generating reports, or synchronizing data to be performed without blocking the main application thread.

Hangfire with .NET: A Reliable Solution for Background Tasks

Modern web applications often require asynchronous and background tasks to enhance the user experience. Tasks like sending emails, generating reports, data synchronization, or periodic cleanup operations should not block the main application thread or cause the user to wait. This is exactly where Hangfire comes in!

In this blog post, we will comprehensively explore what Hangfire is, why you should use it, its main advantages, and how you can integrate it, especially with your ASP.NET Core applications.

What is Hangfire?

Hangfire is an open-source, reliable, and easy-to-use library designed for effortless execution, management, and monitoring of background jobs in .NET applications. It ensures the durable execution of your tasks even if your application server crashes or restarts. Hangfire persists jobs to a storage layer (typically a database), so the application can resume where it left off when it restarts.

Why Should You Use Hangfire?

Manually managing background tasks can be complex and error-prone. Hangfire automates and simplifies this process, offering numerous benefits:

  • Durability: Since jobs are stored in a database, they are not lost if the application crashes or the server restarts. When the application comes back online, the jobs continue to execute.

  • Ease of Use: Its intuitive API makes defining and enqueuing background jobs incredibly simple. You can schedule complex tasks with just a single line of code.

  • Diverse Job Types: Hangfire supports various job types: fire-and-forget, delayed, recurring, and continuation jobs.

  • Monitoring and Management Dashboard: With a built-in web UI dashboard, you can monitor all your background jobs in real-time, retry, delete, or manually trigger them. This dashboard provides significant convenience, especially in production environments.

  • Performance: Jobs can be executed on separate threads or remote servers, which improves the main application's response time.

  • Storage Versatility: It supports various storage backends such as SQL Server, Redis, PostgreSQL, and MongoDB.

Advantages of Hangfire

The primary advantages of using Hangfire enhance the overall quality and manageability of your application:

  • Improved User Experience: By offloading long-running operations to the background, it allows users to navigate quickly within the application.

  • Resource Optimization: Enables CPU or I/O intensive tasks to be executed independently of the main application server.

  • Automation and Reliability: Reduces manual intervention and guarantees that jobs run reliably at specified times or conditions.

  • Scalability: Can work across multiple servers to distribute the workload, helping your application scale.

Using Hangfire with ASP.NET Core

Integrating Hangfire into an ASP.NET Core application is quite easy. Here’s a step-by-step basic setup:

1. Install NuGet Packages:

First, you need to add the necessary NuGet packages to your project:

Install-Package Hangfire.Core
Install-Package Hangfire.AspNetCore
Install-Package Hangfire.SqlServer # or the appropriate package for your database

2. Configure in Startup.cs (or Program.cs):

You need to configure Hangfire in your Program.cs file (or Startup.cs in ASP.NET Core 5 and earlier).

using Hangfire;
using Hangfire.SqlServer;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();

// Add Hangfire Services
builder.Services.AddHangfire(configuration => configuration
    .SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
    .UseSimpleAssemblyNameTypeSerializer()
    .UseRecommendedSerializerSettings()
    .UseSqlServerStorage(builder.Configuration.GetConnectionString("HangfireConnection"), new SqlServerStorageOptions
    {
        CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
        SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
        QueuePollInterval = TimeSpan.Zero,
        UseRecommendedIsolationLevel = true,
        DisableGlobalLocks = true // For distributed environments
    }));

// Add Hangfire Server (the service that will process background jobs)
builder.Services.AddHangfireServer();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

// Add Hangfire Dashboard (optional, but highly recommended)
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
    // You can add authentication to restrict access to the Dashboard.
    // It's also good practice to show the Dashboard only in development environment.
    // Authorization = new [] { new MyAuthorizationFilter() }
});


app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

// Example Background Job Creation
app.MapGet("/send-email", () =>
{
    BackgroundJob.Enqueue(() => Console.WriteLine("Email sent!"));
    return "Email sending job enqueued.";
});

app.MapGet("/schedule-report", () =>
{
    BackgroundJob.Schedule(() => Console.WriteLine("Report generated with delay!"), TimeSpan.FromMinutes(1));
    return "Report job scheduled to run in 1 minute.";
});

app.MapGet("/daily-backup", () =>
{
    // A job that runs every day at 03:00 AM
    RecurringJob.AddOrUpdate("daily-backup", () => Console.WriteLine("Daily backup performed!"), Cron.Daily(3, 0));
    return "Daily backup job configured.";
});


app.Run();

3. Add Connection String:

Add the database connection string that Hangfire will use to your appsettings.json file:

{
  "ConnectionStrings": {
    "HangfireConnection": "Server=(localdb)\\mssqllocaldb;Database=HangfireDb;Integrated Security=True;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

When you first run your application, Hangfire will automatically create the necessary tables in the database.

4. Define Background Jobs:

As shown in the Program.cs example above, you can define different types of jobs using the BackgroundJob class:

  • BackgroundJob.Enqueue(() => Console.WriteLine("Message"));: Fire-and-forget job. Executes immediately.

  • BackgroundJob.Schedule(() => Console.WriteLine("Message"), TimeSpan.FromDays(1));: Delayed job. Executes after a specified delay.

  • RecurringJob.AddOrUpdate("job-id", () => Console.WriteLine("Message"), Cron.Hourly());: Recurring job. Executes regularly based on a CRON expression.

5. Access the Hangfire Dashboard:

After running your application, you can access the Hangfire Dashboard by navigating to https://localhost:[port]/hangfire. On this dashboard, you can view and manage all your active, successful, failed, and enqueued jobs.

Conclusion

Hangfire is an invaluable tool for .NET developers, radically simplifying background task management and enhancing its reliability. With its durability, flexible job types, comprehensive monitoring dashboard, and seamless integration with ASP.NET Core, you can significantly improve your application's performance and user experience.

If you are considering adding long-running or periodic operations to your applications, Hangfire should definitely be at the top of your list!