Core中使用Hangfire
之前使用Quartz.Net,后来发现hangfire对Core的继承更加的好,而且自带管理后台,这就比前者好用太多了。
安装注册
安装
PM> Install-Package Hangfire
Startup.cs,在ConfigureServices
方法中添加注册:
services.AddHangfire(x => x.UseSqlServerStorage("connection string"));
SqlServer是使用这种方式,其他方式见官方的文档及相应插件。
注册完成后,还需要在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即可查看管理后台界面如下:
基本使用
Hangfire的使用非常简单,基本上使用以下几个静态方法:
//执行后台脚本,仅执行一次
BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget!")); //延迟执行后台脚本呢,仅执行一次
BackgroundJob.Schedule(
() => Console.WriteLine("Delayed!"),
TimeSpan.FromDays()); //周期性任务
RecurringJob.AddOrUpdate(
() => Console.WriteLine("Recurring!"),
Cron.Daily); //等上一任务完成后执行
BackgroundJob.ContinueWith(
jobId, //上一个任务的jobid
() => Console.WriteLine("Continuation!"));
注意,周期性使用可以使用Cron表达式。
# ┌───────────── 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的时候会遇到各种问题,比如下列代码:
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后台你会看到如下错误:
错误信息呢大概意思是不能使用接口或者抽象方法类,其实就是因为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());
_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() }
});
参考资料
- Hangfire 官网:https://www.hangfire.io/
- Hangfire DI in .net core : https://stackoverflow.com/questions/41829993/hangfire-dependency-injection-with-net-core
- Demo 地址:https://github.com/JamesYing/BlogsRelatedCodes/tree/master/hangfireDemo
最新文章
- [转载]C++堆栈的入门学习
- centos7安装http服务
- 数组栈的C语言实现
- Lucene/Solr搜索引擎开发笔记 - 第2章 Solr安装与部署(Tomcat篇)
- startssl 申请证书,并在Nginx, apache, Tomcat上使用
- PHP_string
- C#使用SQL存储过程完整流程
- phonegap 使用极光推送实现消息推送
- 第六篇、微信小程序-form组件
- fstab 介绍
- 基于visual Studio2013解决算法导论之052深度优先
- Topcoder口胡记 SRM 562 Div 1 ~ SRM 599 Div 1
- 开始ITGEGE教育社区的视频录制----嵌入式基础知识讲解
- SMO实现
- 洛谷P4016负载平衡
- 自动化测试-19.selenium定位之通过JS修改html写入日期数据以及从文本读取数据实战
- OC相机封装
- java-TreeSet进行排序的2种方式
- Linux下oracle11g 导入导出操作详细
- Spring MVC controller控制器映射无法访问问题!!!
热门文章
- Ajax请求php返回json对象数据中包含有数字索引和字符串索引,在for in循环中取出数据的顺序问题
- EBS xml publisher中文乱码
- vc6.0 PK vs2010
- Android-Java-Thread start run的区别
- [MySQL Tips]:如何删除unique key约束
- SQL Server Extended Events 进阶 3:使用Extended Events UI
- Visual Studio 6 (VC6)连接Team Foundation Server (TFS 2018),实现源代码的版本管理
- [JS] IE下ajax请求不生效或者请求结果不更新
- TextBox 加阴影
- C# VS .NET 版本对应关系