以前使用Quartz.Net,后来发现hangfire对Core的继承更加的好,并且自带管理后台,这就比前者好用太多了。html
安装git
PM> Install-Package Hangfire
Startup.cs,在ConfigureServices
方法中添加注册:github
services.AddHangfire(x => x.UseSqlServerStorage("connection string"));
SqlServer是使用这种方式,其余方式见官方的文档及相应插件。shell
注册完成后,还须要在Configure方法中,添加以下高亮部分的代码:数据库
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } //添加Hangfire app.UseHangfireServer(); app.UseHangfireDashboard();
配置完毕后运行咱们的项目,这时Hangfire会自动在数据库中建立结构,数据库中会新建以下表:

如今在网站根目录+/Hangfire便可查看管理后台界面以下:express
Hangfire的使用很是简单,基本上使用如下几个静态方法:bash
//执行后台脚本,仅执行一次 BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget!")); //延迟执行后台脚本呢,仅执行一次 BackgroundJob.Schedule( () => Console.WriteLine("Delayed!"), TimeSpan.FromDays(7)); //周期性任务 RecurringJob.AddOrUpdate( () => Console.WriteLine("Recurring!"), Cron.Daily); //等上一任务完成后执行 BackgroundJob.ContinueWith( jobId, //上一个任务的jobid () => Console.WriteLine("Continuation!"));
注意,周期性使用可使用Cron表达式。app
# ┌───────────── minute (0 - 59) # │ ┌───────────── hour (0 - 23) # │ │ ┌───────────── day of the month (1 - 31) # │ │ │ ┌───────────── month (1 - 12) # │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday; # │ │ │ │ │ 7 is also Sunday on some systems) # │ │ │ │ │ # │ │ │ │ │ # * * * * * command to execute
Entry | Description | Equivalent to |
---|---|---|
@yearly (or @annually) |
每一年1月3号2:01分运行 | 1 2 3 1 * |
@monthly |
每个月3号2:01分运行 | 1 2 3 * * |
@weekly |
每周日的2:01分运行 | 1 2 * * 0 |
@daily |
天天的2:01分运行 | 1 2 * * * |
@hourly |
每小时的1分运行 | 1 * * * * |
@reboot |
Run at startup | N/A |
在.Net Core中到处是DI,一不当心,你会发现你在使用Hangfire的时候会遇到各类问题,好比下列代码:less
public class HomeController : Controller { private ILogger<HomeController> _logger; public HomeController(ILoggerFactory loggerFactory) { _logger = loggerFactory.CreateLogger<HomeController>(); } public IActionResult Index() { _logger.LogInformation("start index"); BackgroundJob.Enqueue(() => _logger.LogInformation("this a job!")); return View(); } }
项目启动后,你能正常访问,但在Hangfire后台你会看到以下错误:ide
错误信息呢大概意思是不能使用接口或者抽象方法类,其实就是由于Hangfire没有找到实例,那如何让Hangfire支持DI呢?
咱们先建立一个MyActivator
类,使其继承Hangfire.JobActivator
类,代码以下:
public class MyActivator : Hangfire.JobActivator { private readonly IServiceProvider _serviceProvider; public MyActivator(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider; public override object ActivateJob(Type jobType) { return _serviceProvider.GetService(jobType); } }
重写了ActivateJob方法,使其返回的类型从咱们的IServiceProvider中获取。
咱们试着写两个后台脚本,CheckService和TimerService,CheckService的Check方法在执行计划时,会再次调用Hangfire来定时启动TimerService:
CheckService:
public interface ICheckService { void Check(); } public class CheckService : ICheckService { private readonly ILogger<CheckService> _logger; private ITimerService _timeservice; public CheckService(ILoggerFactory loggerFactory, ITimerService timerService) { _logger = loggerFactory.CreateLogger<CheckService>(); _timeservice = timerService; } public void Check() { _logger.LogInformation($"check service start checking, now is {DateTime.Now}"); BackgroundJob.Schedule(() => _timeservice.Timer(), TimeSpan.FromMilliseconds(30)); _logger.LogInformation($"check is end, now is {DateTime.Now}"); } }
TimerService:
public interface ITimerService { void Timer(); } public class TimerService : ITimerService { private readonly ILogger<TimerService> _logger; public TimerService(ILoggerFactory loggerFactory) { _logger = loggerFactory.CreateLogger<TimerService>(); } public void Timer() { _logger.LogInformation($"timer service is starting, now is {DateTime.Now}"); _logger.LogWarning("timering"); _logger.LogInformation($"timer is end, now is {DateTime.Now}"); } }
目前还没法使用,咱们必须在Startup
中注册这2个service:
services.AddScoped<ITimerService, TimerService>();
services.AddScoped<ICheckService, CheckService>();
咱们在HomeController
修改如下:
public IActionResult Index() { _logger.LogInformation("start index"); BackgroundJob.Enqueue<ICheckService>(c => c.Check()); return View(); }
好,一切就绪,只差覆盖原始的Activator了,咱们能够在Startup.cs
中的Configure
方法中使用以下代码:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider) { GlobalConfiguration.Configuration.UseActivator<MyActivator>(new MyActivator(serviceProvider)); …… …… }
默认状况下Configure方法时没有IServiceProvider参数的,请手动添加
再次启动,咱们的Job就会成功执行,截图以下:
401 Unauthorized
未受权错误,缘由是 Hangfire 默认增长了受权配置。解决方式:
增长CustomAuthorizeFilter
:
public class CustomAuthorizeFilter : IDashboardAuthorizationFilter { public bool Authorize([NotNull] DashboardContext context) { //var httpcontext = context.GetHttpContext(); //return httpcontext.User.Identity.IsAuthenticated; return true; } }
Configure
增长配置:
app.UseHangfireDashboard("/hangfire", new DashboardOptions() { Authorization = new[] { new CustomAuthorizeFilter() } });