在Asp.Net Core中使用DI的方式使用Hangfire构建后台执行脚本
最近项目中需要用到后台Job,原有在Windows中我们会使用命令行程序结合计划任务或者直接生成Windows Service,现在.Net Core跨平台了,虽然Linux下也有计划任务,但跟原有方式一样,没撒图形界面,执行结果之类的只能去服务器查看日志。
看了下Hangfire,基本满足于现有需求,有图形UI,注册后台Job也非常简便,考虑之下,就是用它了。
安装注册
Hangfire的使用也非常简单,在项目中先安装Hangfire包:
PM> Install-Package Hangfire
Asp.Net Core项目的话,打开Startup.cs,在ConfigureServices方法中添加注册:
services.AddHangfire(x => x.UseSqlServerStorage("connection string"));
connection string是数据库连接字符串,我用的时Sql Server,你也可以使用Redis,Mysql等其他数据库。
注册完成后,我们在Configure方法中,添加如下代码:
app.UseHangfireServer();
app.UseHangfireDashboard();
好了,等项目启动之后,Hangfire先Migration相关数据结构,项目启动之后,可以通过项目地址+/Hangfire查看是否运行成功,看到如下界面基本没有问题了。

基本使用
Hangfire的使用非常简单,基本上使用以下几个静态方法:
//执行后台脚本,仅执行一次
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!"));
依赖注入
在.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(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就会成功执行,截图如下:

参考资料
- 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
在Asp.Net Core中使用DI的方式使用Hangfire构建后台执行脚本的更多相关文章
- 浅谈ASP.NET Core中的DI
DI的一些事 传送门马丁大叔的文章 什么是依赖注入(DI: Dependency Injection)? 依赖注入(DI)是一种面向对象的软件设计模式,主要是帮助开发人员开发出松耦合的应用程序 ...
- asp.net core 中灵活的配置方式
asp.net core支持外部文件和命令行参数方式来配置系统运行所需要的配置信息,我们从下面两个常用场景来具体说下具体使用方法. 一.监听地址及端口配置 1,命令行方式 asp.net core系统 ...
- ASP.NET Core中的OWASP Top 10 十大风险-跨站点脚本攻击 (XSS)
不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址 本博文翻译自: https://dotnetcoretutorials.com/201 ...
- Asp.Net Core中HttpClient的使用方式
在.Net Core应用开发中,调用第三方接口也是常有的事情,HttpClient使用人数.使用频率算是最高的一种了,在.Net Core中,HttpClient的使用方式随着版本的升级也发生了一些变 ...
- ASP.NET Core中的依赖注入(3): 服务的注册与提供
在采用了依赖注入的应用中,我们总是直接利用DI容器直接获取所需的服务实例,换句话说,DI容器起到了一个服务提供者的角色,它能够根据我们提供的服务描述信息提供一个可用的服务对象.ASP.NET Core ...
- ASP.NET Core 中的依赖注入 [共7篇]
一.控制反转(IoC) ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了 ...
- 在ASP.NET Core中构建路由的5种方法
原文链接 :https://stormpath.com/blog/routing-in-asp-net-core 在ASP.NET Core中构建路由的5种方法 原文链接 :https://storm ...
- C#调用接口注意要点 socket,模拟服务器、客户端通信 在ASP.NET Core中构建路由的5种方法
C#调用接口注意要点 在用C#调用接口的时候,遇到需要通过调用登录接口才能调用其他的接口,因为在其他的接口需要在登录的状态下保存Cookie值才能有权限调用, 所以首先需要通过调用登录接口来保存c ...
- ASP.NET Core中Middleware的使用
https://www.cnblogs.com/shenba/p/6361311.html ASP.NET 5中Middleware的基本用法 在ASP.NET 5里面引入了OWIN的概念,大致意 ...
随机推荐
- 记一个常见的ms sql server中取第N条记录的方法
前言 好好学习,天天向上. 正文 好像也是一个不难的问题,刚视频里看到的,就记一下吧. 下面是表中原始的数据结构,做了一个倒叙排序: select * from Employee order by S ...
- CSS中层叠和CSS的7阶层叠水平(上篇)
今天搜索资料时,忽然发现了以前没注意的一个知识点,所以拖过来搞一搞,这个知识点叫做CSS的7阶层叠水平 在说这个知识之前,我们必须要先了解一个东西以便于我们更好的理解CSS的7阶层叠水平 这个东西就是 ...
- checkbox在vue中的用法小结
关于checkbox多选框是再常见不过的了,几乎很多地方都会用到,这两天在使用vue框架时需要用到checkbox多选功能,实在着实让我头疼,vue和原生checkbox用法不太一样,之前对于vue插 ...
- 【代码笔记】Web-CSS-CSS Display
一,效果图. 二,代码. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...
- wordcloud2.js
https://blogs.msdn.microsoft.com/dotnet/2019/01/10/announcing-ml-net-0-9-machine-learning-for-net/ h ...
- Kotlin入门(30)多线程交互
Android开发时常会遇到一些耗时的业务场景,比如后台批量处理数据.访问后端服务器接口等等,此时为了保证界面交互的及时响应,必须通过线程单独运行这些耗时任务.简单的线程可使用Thread类来启动,无 ...
- Linux & Windows 环境下 Redis 安装与基本配置
索引: 目录索引 参看代码 GitHub: redis.txt 一.Linux (DeepinOS) 环境 .安装Redis服务 sudo apt-get install redis-server . ...
- Linux查杀stopped进程
在Linux系统下面,top命令可以查看查看stopped进程.但是不能查看stopped进程的详细信息.那么如何查看stopped 进程,并且杀掉这些stopped进程呢? ps -e j | ...
- cannot be run because the QueueReader subsystem failed to load
前阵子一数据库服务器的事务日志开始暴增,当时使用下面脚本检查发现该数据库的log_reuse_wait_desc 一直处于REPLICATION状态, 也就是说在事务复制过程中,与发布相关的事务仍未传 ...
- ES6使用的一些方法
查找数组中符合条件的所有记录 var list=[ {id:1,name:"张三"}, {id:2,name:"李四"}, {id:3,name:"王 ...