最近项目中需要用到后台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就会成功执行,截图如下:

参考资料

在Asp.Net Core中使用DI的方式使用Hangfire构建后台执行脚本的更多相关文章

  1. 浅谈ASP.NET Core中的DI

    DI的一些事 传送门马丁大叔的文章 什么是依赖注入(DI: Dependency Injection)?     依赖注入(DI)是一种面向对象的软件设计模式,主要是帮助开发人员开发出松耦合的应用程序 ...

  2. asp.net core 中灵活的配置方式

    asp.net core支持外部文件和命令行参数方式来配置系统运行所需要的配置信息,我们从下面两个常用场景来具体说下具体使用方法. 一.监听地址及端口配置 1,命令行方式 asp.net core系统 ...

  3. ASP.NET Core中的OWASP Top 10 十大风险-跨站点脚本攻击 (XSS)

    不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址 本博文翻译自: https://dotnetcoretutorials.com/201 ...

  4. Asp.Net Core中HttpClient的使用方式

    在.Net Core应用开发中,调用第三方接口也是常有的事情,HttpClient使用人数.使用频率算是最高的一种了,在.Net Core中,HttpClient的使用方式随着版本的升级也发生了一些变 ...

  5. ASP.NET Core中的依赖注入(3): 服务的注册与提供

    在采用了依赖注入的应用中,我们总是直接利用DI容器直接获取所需的服务实例,换句话说,DI容器起到了一个服务提供者的角色,它能够根据我们提供的服务描述信息提供一个可用的服务对象.ASP.NET Core ...

  6. ASP.NET Core 中的依赖注入 [共7篇]

    一.控制反转(IoC) ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了 ...

  7. 在ASP.NET Core中构建路由的5种方法

    原文链接 :https://stormpath.com/blog/routing-in-asp-net-core 在ASP.NET Core中构建路由的5种方法 原文链接 :https://storm ...

  8. C#调用接口注意要点 socket,模拟服务器、客户端通信 在ASP.NET Core中构建路由的5种方法

    C#调用接口注意要点   在用C#调用接口的时候,遇到需要通过调用登录接口才能调用其他的接口,因为在其他的接口需要在登录的状态下保存Cookie值才能有权限调用, 所以首先需要通过调用登录接口来保存c ...

  9. ASP.NET Core中Middleware的使用

    https://www.cnblogs.com/shenba/p/6361311.html   ASP.NET 5中Middleware的基本用法 在ASP.NET 5里面引入了OWIN的概念,大致意 ...

随机推荐

  1. 深度学习框架Keras介绍及实战

    Keras 是一个用 Python 编写的高级神经网络 API,它能够以 TensorFlow, CNTK, 或者 Theano 作为后端运行.Keras 的开发重点是支持快速的实验.能够以最小的时延 ...

  2. Perl IO:文件锁

    文件锁 当多个进程或多个程序都想要修同一个文件的时候,如果不加控制,多进程或多程序将可能导致文件更新的丢失. 例如进程1和进程2都要写入数据到a.txt中,进程1获取到了文件句柄,进程2也获取到了文件 ...

  3. 触发器 评论折叠显示(jquery)

    触发器   评论折叠显示(jquery)   子页面 : @if(Model?.count>0) {      var i=1;      var n=model.count-2      va ...

  4. git合并两个不同的仓库

    目前开发是2个仓库,线上仓库online_a(对应的branch分支为online),测试环境online_b(对应的branch分支为demo),测试环境需要时刻保持onine_a上的最新稳定稳定代 ...

  5. 教我徒弟Android开发入门(四)

    本期知识点: 两大常用布局的简单介绍 在我们的APP使用第三方库 Android Studio常用快捷键 一.两大常用布局 1.LinearLayout线性布局 线性布局,可以垂直显示或者水平显示,设 ...

  6. WEB前端 HTML

    目录 WEB前端 HTML WEB前端 HTML TOC 什么是html? html的固有结构 注释 什么是标签? 标签分类 什么是标签属性? 适用于大多数HTML标签的属性 常用标签 常用引用标签 ...

  7. springboot之配置文件

    springboot在加载配置文件的时候是有先后顺序的,了解加载配置文件的先后顺序,可以减少编写程序出现错误 1 springboot加载配置文件的先后顺序如下: SpringApplication将 ...

  8. Apex 中操作用户和组

    用户和组概述 Salesforce中对于用户的定义主要体现于两个对象:用户(User)和组(Group).组的成员可以是用户也可以是另一个组. Salesforce中的组可以有多种表示方法,比如队列( ...

  9. C# 动态生成word文档

    本文以一个简单的小例子,简述利用C#语言开发word表格相关的知识,仅供学习分享使用,如有不足之处,还请指正. 在工程中引用word的动态库 在项目中,点击项目名称右键-->管理NuGet程序包 ...

  10. DedeCMS清空删除所有文档后新建文档信息ID从1开始

    方法一.登录织梦后台,找到系统->系统设置->SQL命令行工具 分别运行以下命令: 清除表中的数据,删除所有文章: truncate table `dede_arctiny`; trunc ...