Hangfire是一个开源的.NET任务调度框架,提供了内置集成化的控制台,可以直观明了的查看作业调度情况,并且Hangfire不需要依赖于单独的应用程序执行,并且支持持久性存储。相对于Quartz.NET框架,Hangfire控制面板不仅提供监控,也可以手动的触发执行定时任务。本文主要介绍 .NET Core 3.1(C#)中Hangfire定时任务组件安装配置及使用。

1、安装引用Hangfire

1)使用Nuget界面管理器

搜索 "Hangfire.AspNetCore"、“Hangfire.Core”、“Hangfire.Dashboard.BasicAuthorization”和 “Hangfire.MySqlStorage”,在列表中分别找到它,点击"安装"

相关文档VS(Visual Studio)中Nuget的使用

2)使用Package Manager命令安装

PM> Install-Package Hangfire.AspNetCore
PM> Install-Package Hangfire.Core
PM> Install-Package Hangfire.Dashboard.BasicAuthorization
PM> Install-Package Hangfire.MySqlStorage

3)使用.NET CLI命令安装

> dotnet add package Hangfire.AspNetCore
> dotnet add package Hangfire.Core
> dotnet add package Hangfire.Dashboard.BasicAuthorization
> dotnet add package Hangfire.MySqlStorage

2、appsettings.json配置文件

appsettings.json配置文件中添加Hangfire的相关配置,内容如下:

  "HangFire": {
"Connection": "Server=127.0.0.1;uid=root;pwd=website;database=Hangfire_DB;AllowLoadLocalInfile=true;Allow User Variables=True;",
"pathMatch": "/hangfire",
"Login": "login",
"PasswordClear": "pwd"
},

相关文档:NET Core使用ConfigurationBuilder读取appsettings.json配置文件

3、Hangfire配置及使用

1)定义扩展方法

HangfireMiddleware.cs:

using Hangfire;
using Hangfire.Dashboard.BasicAuthorization;
using Microsoft.AspNetCore.Builder;
using System;
using System.Collections.Generic;
using System.Text;
namespace WebApplication1
{
    //任务调度中间件
    public static class HangfireMiddleware
    {
        public static void UseHangfireMiddleware(this IApplicationBuilder app)
        {
            if (app == null) throw new ArgumentNullException(nameof(app));
            //app.UseHangfireServer(); //配置服务//ConfigureOptions()
            app.UseHangfireDashboard(HangfireSetup.Configuration["HangFire:pathMatch"], HfAuthor()); //配置面板
            BackgroundJob.Enqueue(() => Console.WriteLine("Hello world from Hangfire!"));            
            HangfireService(); //配置各个任务
        }
        /// <summary>
        ///     配置账号模板信息
        /// </summary>
        /// <returns></returns>
        public static DashboardOptions HfAuthor()
        {
            var filter = new BasicAuthAuthorizationFilter(
                new BasicAuthAuthorizationFilterOptions
                {
                    SslRedirect = false,
                    RequireSsl = false,
                    LoginCaseSensitive = false,
                    Users = new[]
                    {
                        new BasicAuthAuthorizationUser
                        {
                            Login =HangfireSetup.Configuration["HangFire:Login"], //可视化的登陆账号
                            PasswordClear =HangfireSetup.Configuration["HangFire:PasswordClear"]  //可视化的密码
                        }
                    }
                });
            return new DashboardOptions
            {
                Authorization = new[] { filter }
            };
        }
        #region 配置服务
        public static void HangfireService()
        {
            // "0 0 1 * * ? " 每天凌晨一点执行
            RecurringJob.AddOrUpdate(() => Console.WriteLine("{0} Recurring job completed successfully!", DateTime.Now.ToString()), "0 0 1 * * ? ", TimeZoneInfo.Local);
            // "0 0 7 * * ? " 每天早上七点执行定时任务
            RecurringJob.AddOrUpdate(() => Console.WriteLine("{0} Recurring job completed successfully!", DateTime.Now.ToString()), "0 0 7 * * ? ",
                TimeZoneInfo.Local);
        }
        #endregion
    }
}

HangfireSetup.cs:

using Hangfire;
using Hangfire.MySql;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using System.Transactions;
namespace WebApplication1
{
    /// <summary>
    ///     任务调度
    /// </summary>
    public static class HangfireSetup
    {
        private static IConfigurationRoot _configuration;
        public static IConfigurationRoot Configuration
        {
            get
            {
                if (_configuration == null)
                {
                    var builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");
                    _configuration = builder.Build();
                }
                return _configuration;
            }
            set
            {
                _configuration = value;
            }
        }
        public static void AddHangfireSetup(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
            if (services == null) throw new ArgumentNullException(nameof(services));
            services.AddHangfire(configuration => configuration
                .SetDataCompatibilityLevel(CompatibilityLevel.Version_170)//此方法 只初次创建数据库使用即可
                .UseSimpleAssemblyNameTypeSerializer()
                .UseRecommendedSerializerSettings()
                .UseStorage(new MySqlStorage(HangfireSetup.Configuration["HangFire:Connection"], new MySqlStorageOptions
                {
                    TransactionIsolationLevel = IsolationLevel.ReadCommitted, //事务隔离级别。默认是读取已提交
                    QueuePollInterval = TimeSpan.FromSeconds(15), //- 作业队列轮询间隔。默认值为15秒。
                    JobExpirationCheckInterval = TimeSpan.FromHours(1),
                    CountersAggregateInterval = TimeSpan.FromMinutes(5),
                    PrepareSchemaIfNecessary = false, // 如果设置为true,则创建数据库表。默认是true
                    DashboardJobListLimit = 50000,
                    TransactionTimeout = TimeSpan.FromMinutes(1),
                    TablesPrefix = "Hangfire"
                })));
            services.AddHangfireServer(opt =>
            {
                opt.Queues = new[] { "Job", "cjavapy" }; //队列名称,只能为小写
                opt.WorkerCount = Environment.ProcessorCount * 5; //并发任务
                opt.ServerName = "HangfireServer"; //代表服务名称
            });
        }
    }
}

2)Startup.cs中的配置

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace WebApplication1
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<HangFireModel>(HangfireSetup.Configuration.GetSection("HangFire"));
            services.AddHangfireSetup();//任务调度c
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseHangfireMiddleware();//Job
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });
        }
    }
}

3)appsettings.json配置文件

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "HangFire": {
    "Connection": "Server=127.0.0.1;uid=root;pwd=website;database=Hangfire_DB;AllowLoadLocalInfile=true;Allow User Variables=True;",
    "pathMatch": "/hangfire",
    "Login": "login",
    "PasswordClear": "pwd"
  }
}

4、运行访问控制面板

首次运行成功后,打开MySQL数据库可以看到Hangfire已经自动创建了定时任务的一些定时任务列表,定时队列,服务,状态等相关的数据表,运行项目访问https://localhost:端口号/hangfire/,则可以看到控制面板,如下图,

httpswwwcjavapycom

5、Hangfire的使用及相关文档

1)Fire-and-forget jobs(基于队列的任务处理)

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

2)Delayed jobs(延迟任务执行)

var jobId = BackgroundJob.Schedule(() => Console.WriteLine("Delayed!"), TimeSpan.FromDays(7));

3)Recurring jobs(定时任务执行)

RecurringJob.AddOrUpdate(() => Console.WriteLine("Recurring!"), Cron.Daily);

4)Continuations(延续性任务执行)

BackgroundJob.ContinueWith(jobId , () => Console.WriteLine("Continuation!"));

5)Batches(多任务批处理)

var batchId = BatchJob.StartNew(x =>
{
x.Enqueue(() => Console.WriteLine("Job 1"));
x.Enqueue(() => Console.WriteLine("Job 2"));
})

6)Batch Continuations(上个任务完成继续处理)

BatchJob.ContinueWith(batchId, x =>
{
x.Enqueue(() => Console.WriteLine("Last Job"));
});

7)参考文档

官网地址:https://www.hangfire.io/

GitHub源码:https://github.com/HangfireIO/Hangfire

中文文档:https://www.bookstack.cn/read/Hangfire-zh-official/README.md 

GitHub使用示例源码:https://github.com/HangfireIO/Hangfire.Samples(包括控制台应用程序,window服务,ASP.NET MVC,WebForm)

推荐文档