一、创建 .NET 8 项目
首先创建一个 .NET 8 项目(ASP.NET Core Web 应用或控制台应用),这里以 ASP.NET Core Web API 为例。
二、安装必要的 NuGet 包
核心包(适用于 ASP.NET Core)
Install-Package Hangfire.AspNetCore
存储后端(选择一个)
Install-Package Hangfire.SqlServer # SQL Server
Install-Package Hangfire.Redis.StackExchange # Redis
Install-Package Hangfire.PostgreSql # PostgreSQL
其他拓展
Install-Package Microsoft.Data.SqlClient
Install-Package Swashbuckle.AspNetCore
三、完整配置步骤(.NET 8 + SQL Server)
-
配置连接字符串
在 appsettings.json 中添加数据库连接:
需先创建一个数据库Windows本机连接
{
"ConnectionStrings": {
"HangfireConnection": "Server=localhost;Database=HangfireNet8;Integrated Security=True;TrustServerCertificate=True"
}
}IP账号密码连接
"ConnectionStrings": {
"HangfireConnection": "Server=127.0.0.1;Database=HangfireDB;User Id=sa;Password=123456;TrustServerCertificate=True;Encrypt=False"
} -
配置 Program.cs
csharp
using Hangfire;
using Hangfire.Dashboard;
using Hangfire.SqlServer;
using Microsoft.Extensions.Logging;
using System.Net;
var builder = WebApplication.CreateBuilder(args);
// 添加 Hangfire 服务
builder.Services.AddHangfire(configuration => configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
// 配置 SQL Server 存储
.UseSqlServerStorage(builder.Configuration.GetConnectionString("HangfireConnection"), new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
DisableGlobalLocks = true,
EnableHeavyMigrations = true
})
);
// 添加 Hangfire 服务器
builder.Services.AddHangfireServer(options =>
{
options.WorkerCount = Math.Max(Environment.ProcessorCount * 5, 10);
options.Queues = new[] { "high", "medium", "low" };
options.ShutdownTimeout = TimeSpan.FromMinutes(1);
});
// 添加控制器和Swagger服务
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// 注册应用服务
builder.Services.AddScoped<ITaskService, TaskService>();
var app = builder.Build();
var isDevelopment = app.Environment.IsDevelopment();
// 配置HTTP请求管道
if (isDevelopment)
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
// 启用 Hangfire 仪表板
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
Authorization = new[] { new HangfireAuthFilter(isDevelopment) }
});
// 定义任务
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var taskService = services.GetRequiredService<ITaskService>();
// 1. 即时任务
BackgroundJob.Enqueue(() => taskService.ProcessData("initial"));
// 2. 延迟任务(30分钟后执行)
BackgroundJob.Schedule(
() => taskService.SendNotification("delayed"),
TimeSpan.FromMinutes(1)
);
// 3. 循环任务(每小时执行一次)
RecurringJob.AddOrUpdate(
"hourly-cleanup",
() => taskService.CleanupResources(),
Cron.Hourly,
TimeZoneInfo.Local
);
// 4. 延续任务
var parentJobId = BackgroundJob.Enqueue(() => taskService.ProcessOrder(1001));
BackgroundJob.ContinueWith(
parentJobId,
() => taskService.CompleteOrder(1001)
);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "注册Hangfire任务时发生错误");
}
}
app.MapControllers();
app.Run();
// 自定义授权过滤器 - 修复空值问题
public class HangfireAuthFilter : IDashboardAuthorizationFilter
{
private readonly bool _isDevelopment;
public HangfireAuthFilter(bool isDevelopment)
{
_isDevelopment = isDevelopment;
}
public bool Authorize(DashboardContext context)
{
// 确保上下文不为空
if (context == null)
return false;
// 获取HTTP上下文并检查
var httpContext = context.GetHttpContext();
if (httpContext == null)
return false;
// 开发环境直接允许访问
if (_isDevelopment)
return true;
// 生产环境检查是否为本地访问
var localIpAddress = httpContext.Connection.LocalIpAddress;
if (localIpAddress == null)
return false;
// 明确检查是否为回环地址(IPv4和IPv6)
return IPAddress.IsLoopback(localIpAddress);
}
}
// 任务服务接口
public interface ITaskService
{
void ProcessData(string data);
void SendNotification(string message);
void CleanupResources();
void ProcessOrder(int orderId);
void CompleteOrder(int orderId);
}
// 任务服务实现
public class TaskService : ITaskService
{
private readonly ILogger<TaskService> _logger;
// 确保日志服务不为空
public TaskService(ILogger<TaskService> logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public void ProcessData(string data)
{
if (string.IsNullOrEmpty(data))
throw new ArgumentException("数据不能为空", nameof(data));
_logger.LogInformation("处理数据: {Data}", data);
}
public void SendNotification(string message)
{
if (string.IsNullOrEmpty(message))
throw new ArgumentException("消息不能为空", nameof(message));
_logger.LogInformation("发送通知: {Message}", message);
}
public void CleanupResources()
{
_logger.LogInformation("清理资源于 {Time}", DateTime.Now);
}
public void ProcessOrder(int orderId)
{
if (orderId <= 0)
throw new ArgumentOutOfRangeException(nameof(orderId), "订单ID必须大于0");
_logger.LogInformation("处理订单: {OrderId}", orderId);
}
public void CompleteOrder(int orderId)
{
if (orderId <= 0)
throw new ArgumentOutOfRangeException(nameof(orderId), "订单ID必须大于0");
_logger.LogInformation("订单完成: {OrderId}", orderId);
}
}
四、数据库初始化
首次运行应用时,Hangfire 会自动在指定的数据库中创建所需的表结构(约 15 张表),无需手动创建。
五、访问 Hangfire 仪表板
启动应用后,访问 https://localhost:端口/hangfire 即可打开管理界面,在这里可以:
查看所有任务的执行状态
手动触发、暂停或删除循环任务
重试失败的任务
监控服务器状态和性能