在 WPF 项目中集成 Hangfire

发布于:2025-02-24 ⋅ 阅读:(14) ⋅ 点赞:(0)

以下是在 WPF 项目中集成 Hangfire 的完整指南,涵盖核心功能(定时任务、后台任务、重试机制)和代码示例:


一、Hangfire 简介

  • 定位:开源的 .NET 任务调度框架,专注于 定时任务后台任务 和 重试机制
  • 适用场景
    • 定时发送邮件、报表生成等重复性任务。
    • 长时间运行的异步任务(如文件导出、数据同步)。
    • 需要任务失败自动重试的场景。
  • 特点
    • 支持 SQL Server、Redis、MongoDB 等多种存储。
    • 提供直观的 Web 界面监控任务状态(需配合 Hangfire Dashboard)。
    • 轻量级(核心库仅依赖 System.Threading)。

二、在 WPF 项目中使用 Hangfire

1. 安装依赖

通过 NuGet 安装 Hangfire.Core 和存储提供程序(以 SQL Server 为例):


Install-Package Hangfire.Core -Version 1.9.0
Install-Package Hangfire.SqlServer -Version 1.9.0
2. 配置 Hangfire

在 WPF 项目的入口类(如 App.xaml.cs)中初始化 Hangfire:


using Hangfire;
using Hangfire.SqlServer;

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        
        // 配置 SQL Server 数据库连接
        var connectionString = "YourSqlConnection";
        GlobalConfiguration.Configuration
            .UseSqlServerStorage(connectionString)
            .UseConsoleLogger(); // 输出日志到控制台
        
        // 启动 Hangfire 服务(非 Web 环境需手动启动)
        using (var server = new BackgroundJobServer())
        {
            server.Start();
        }
    }
}

三、定义任务

方式一:使用方法委托

// 定义简单任务
RecurringJob.AddOrUpdate(
    "SendDailyReport",
    () => SendDailyReport(),
    "0 0 6 * * *"); // 每天 6:00 执行

// 定义带参数的任务
RecurringJob.AddOrUpdate(
    "ProcessOrder",
    (orderId) => ProcessOrder(orderId),
    "0 */5 * * *",
    new { orderId = 123 });
方式二:实现 IJob 接口

public class SendEmailJob : IJob
{
    public void Execute(IJobExecutionContext context)
    {
        // 发送邮件逻辑
        Console.WriteLine("Email sent to: " + context.JobData["Recipient"]);
    }
}

// 调度任务
BackgroundJob.Enqueue(new SendEmailJob { Recipient = "user@example.com" });

四、任务调度与执行

4.1 启动调度器

在 WPF 启动时启动后台任务服务:


var server = new BackgroundJobServer();
server.Start();
4.2 手动触发任务

// 立即执行一次任务
BackgroundJob.Enqueue(() => DoSomething());

// 延迟执行任务(5秒后)
BackgroundJob.Schedule(() => DoSomething(), TimeSpan.FromSeconds(5));
4.3 重试机制

通过 EnqueueWithRetry 实现自动重试:


BackgroundJob.EnqueueWithRetry(
    () => RiskyOperation(),
    retry: 3, // 最大重试次数
    delay: TimeSpan.FromSeconds(30), // 重试间隔
    onException: ex => ex is IOException); // 仅在 IOException 时重试

五、WPF UI 集成

5.1 显示任务状态

通过 Hangfire Dashboard(需安装 Hangfire.AspNetCore 并配置 Web 端):


Install-Package Hangfire.AspNetCore

在 ASP.NET Core 项目中启用 Dashboard:


public void ConfigureServices(IServiceCollection services)
{
    services.AddHangfireServer();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseHangfireDashboard("/hangfire");
}
5.2 在 WPF 中调用 Hangfire API

通过 HTTP 请求与 Hangfire 交互(需启用 CORS):


private async void btnSchedule_Click(object sender, RoutedEventArgs e)
{
    using (var client = new HttpClient())
    {
        var content = new StringContent(
            JsonConvert.SerializeObject(new { JobName = "SendReport", Schedule = "0 0 6 * * *" }),
            Encoding.UTF8,
            "application/json");
        
        var response = await client.PostAsync("http://localhost:5000/hangfire/api/jobs/schedule", content);
        if (response.IsSuccessStatusCode)
        {
            MessageBox.Show("Task scheduled successfully!");
        }
    }
}

六、持久化配置

6.1 使用 SQL Server 存储

在 app.xaml.cs 中配置连接字符串:


var connectionString = "Data Source=.\sqlserver;Initial Catalog=HangfireDb;Integrated Security=True";
GlobalConfiguration.Configuration
    .UseSqlServerStorage(connectionString)
    .WithTablePrefix("Hangfire"); // 自定义表前缀(可选)
6.2 初始化数据库

运行以下命令创建 Hangfire 表:


dotnet ef database update

七、示例:完整 WPF 项目

项目结构
  • Tasks.cs: 定义任务逻辑
  • MainWindow.xaml.cs: WPF 界面集成
  • App.xaml.cs: Hangfire 初始化
关键代码片段

Tasks.cs:


public class EmailService
{
    public void SendDailyReport()
    {
        Console.WriteLine("Generating daily report...");
        // 实际发送邮件逻辑
    }
}

public class OrderProcessor
{
    public void ProcessOrder(int orderId)
    {
        Console.WriteLine($"Processing order {orderId}...");
        // 模拟失败操作
        if (orderId % 2 == 0)
            throw new InvalidOperationException("Order processing failed.");
    }
}

MainWindow.xaml.cs:


public partial class MainWindow : Window
{
    private readonly IBackgroundJobClient _jobClient;

    public MainWindow()
    {
        InitializeComponent();
        
        // 初始化 Hangfire 客户端
        _jobClient = new BackgroundJobClient();
        
        // 绑定按钮事件
        btnSchedule.Click += BtnSchedule_Click;
        btnRetry.Click += BtnRetry_Click;
    }

    private void BtnSchedule_Click(object sender, RoutedEventArgs e)
    {
        // 调度每日报告任务
        _jobClient.Enqueue(() => EmailService.SendDailyReport());
        MessageBox.Show("Daily report task scheduled!");
    }

    private void BtnRetry_Click(object sender, RoutedEventArgs e)
    {
        // 手动触发失败任务的重新尝试
        var failedJobs = _jobClient.GetFailedJobs(0, 100);
        foreach (var job in failedJobs)
        {
            _jobClient.RetryJob(job.Id);
        }
    }
}

八、核心优势对比

特性 Hangfire 其他框架(如 Elsa Workflow)
专注领域 任务调度、后台任务、重试机制 流程编排、状态管理
执行模式 轻量级后台线程 + 分布式调度 单次或长时间运行工作流实例
持久化 支持 SQL、Redis 等多种存储 依赖 WF 持久化提供程序
社区生态 成熟,文档齐全 较小众(如 Elsa 社区支持较好)

适用场景

  • 需要定时任务:如每日报表、定时通知。
  • 异步任务处理:如文件上传、长耗时计算。
  • 故障恢复:自动重试失败任务,无需人工干预。