当前位置: 首页 > news >正文

在Quartz.Net中使用Scoped Service

refs:

Creating a Quartz.NET hosted service with ASP.NET Core

Using scoped services inside a Quartz.NET hosted service with ASP.NET Core

本文基于上面2个链接的文章翻译攥写。

在Quartz.Net中无法使用scoped service比如DbContext,一般IJob只能是单例模式或Transient模式;

1)为了使用scoped servcie 一般是注入IServiceProvice,然后创建scope环境获取实例。

比如:

public class EmailReminderJob : IJob
{private readonly IServiceProvider _provider;public EmailReminderJob( IServiceProvider provider){_provider = provider;}public Task Execute(IJobExecutionContext context){using(var scope = _provider.CreateScope()){var dbContext = scope.ServiceProvider.GetService<AppDbContext>();var emailSender = scope.ServiceProvider.GetService<IEmailSender>();// fetch customers, send email, update DB}return Task.CompletedTask;}
}

在很多场景下这个是可行的,此时IJob依然在DI中是单例模式。

2)创建一个辅助任务

不直接在IJob中实现,而是通过一个QuartzJobRunner的任务间接实现,在次任务中创建新的任务来实现;

QuartzJobRunner.依然是单例模式,这样就不用担心会被 disposed掉.

services.AddSingleton<QuartzJobRunner>();

QuartzJobRunner中创建一个实例化的新IJob并执行:

using Microsoft.Extensions.DependencyInjection;
using Quartz;
using System;
using System.Threading.Tasks;public class QuartzJobRunner : IJob
{private readonly IServiceProvider _serviceProvider;public QuartzJobRunner(IServiceProvider serviceProvider){_serviceProvider = serviceProvider;}public async Task Execute(IJobExecutionContext context){using (var scope = _serviceProvider.CreateScope()){var jobType = context.JobDetail.JobType;var job = scope.ServiceProvider.GetRequiredService(jobType) as IJob;await job.Execute(context);}}
}

这么做有2个优点:

  • 我们注册EmailReminderJob 为scoped service,并直接注入依赖到其构造方法中;
  • 我们可以将其他跨领域问题转移到QuartzJobRunner类中.

 由于job的实例源自 scoped IServiceProvder,所以可以在构造方法中使用 scoped services

如果你不熟悉DI范围问题,那么理解这些问题可能会很棘手。

[DisallowConcurrentExecution]
public class EmailReminderJob : IJob
{private readonly AppDbContext _dbContext;private readonly IEmailSender _emailSender;public EmailReminderJob(AppDbContext dbContext, IEmailSender emailSender){_dbContext = dbContext;_emailSender = emailSender;}public Task Execute(IJobExecutionContext context){// fetch customers, send email, update DBreturn Task.CompletedTask;}
}

这些 IJob 实现可以注册为任何生命周期(scoped or transient),当然 JobSchedule 依然是单例:

services.AddScoped<EmailReminderJob>();
services.AddSingleton(new JobSchedule(jobType: typeof(EmailReminderJob),cronExpression: "0 0 12 * * ?")); // every day at noon

QuartzJobRunner 处理跨界问题。

This example is obviously very basic. If the code here looks ok to you, I suggest watching Jimmy Bogard's "Six Little Lines of Fail" talk, which describes some of the issues!

public class QuartzJobRunner : IJob
{private readonly IServiceProvider _serviceProvider;public QuartzJobRunner(IServiceProvider serviceProvider){_serviceProvider = serviceProvider;}public async Task Execute(IJobExecutionContext context){using (var scope = _serviceProvider.CreateScope()){var jobType = context.JobDetail.JobType;var job = scope.ServiceProvider.GetRequiredService(jobType) as IJob;var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();var messageBus = scope.ServiceProvider.GetRequiredService<IBus>();await job.Execute(context);// job completed, save dbContext changesawait dbContext.SaveChangesAsync();// db transaction succeeded, send messagesawait messageBus.DispatchAsync();}}
}

QuartzJobRunner 以上实现类似前面的,但是我们创建job后,从DI容器中获取了 DbContext和messageBus,等执行完job后再保存到db并且发送消息到事件总线。 .

把这些方法放在 QuartzJobRunner 中可以减少在具体 IJob中的实现,并且更容易实现其他模式。

这里展示的方法(使用中间的QuartzJobRunner类),主要有两个原因:

  • 您的其他IJob实现不需要任何关于创建作用域的基础架构的知识,只需要避免标准构造函数注入
  • IJobFactory不必做任何特殊的事情来处理处理处理工作。QuartzJobRunner通过创建和处理作用域来隐式地处理这个问题。

其他实现方法见 

Matthew Abbot demonstrates an approach in this gist

由于您必须匹配的接口API,它有点笨重,但可以说它更接近于您应该实现它的方式!就我个人而言,我认为我会坚持QuartzJobRunner的方法,但选择最适合你的方法。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Vue:使用html2canvas将数据导出到PDF上(含分页)
  • docker部署xxl-job
  • Shell脚本-DNS域名解析格式化
  • Element学习(布局组件、案例操作)(4)
  • Android:Uniapp平台中接入即构RTC+相芯美颜
  • Linux 下 perf 的使用
  • Kafka整合SpringBoot
  • HookNet- 用于病理全切片图像的多分辨率语义分割模型|顶刊精析·24-08-08
  • 9.1 迭装饰器的定义与使用:给你的 Python 代码加点“魔法”
  • 服务器启动jar包的时候报”no main manifest attribute“异常(快捷解决)
  • 数据加密-AES数据加密及C#实现
  • 为什么在网页编辑文字时键盘输入换行要停顿一下网页才显示
  • MaxKB:基于 LLM大语言模型的知识库问答系统实操
  • 部署服务器项目及发布
  • Spring统一处理请求响应与异常
  • [ 一起学React系列 -- 8 ] React中的文件上传
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • 【402天】跃迁之路——程序员高效学习方法论探索系列(实验阶段159-2018.03.14)...
  • 2017届校招提前批面试回顾
  • CSS 三角实现
  • flask接收请求并推入栈
  • Java读取Properties文件的六种方法
  • js操作时间(持续更新)
  • JS学习笔记——闭包
  • k8s 面向应用开发者的基础命令
  • magento2项目上线注意事项
  • php中curl和soap方式请求服务超时问题
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • Python_OOP
  • ViewService——一种保证客户端与服务端同步的方法
  • 后端_MYSQL
  • 湖南卫视:中国白领因网络偷菜成当代最寂寞的人?
  • 入职第二天:使用koa搭建node server是种怎样的体验
  • 使用Swoole加速Laravel(正式环境中)
  • 我感觉这是史上最牛的防sql注入方法类
  • 我有几个粽子,和一个故事
  • mysql 慢查询分析工具:pt-query-digest 在mac 上的安装使用 ...
  • 仓管云——企业云erp功能有哪些?
  • ​埃文科技受邀出席2024 “数据要素×”生态大会​
  • ‌JavaScript 数据类型转换
  • # 数论-逆元
  • #HarmonyOS:基础语法
  • #WEB前端(HTML属性)
  • #微信小程序:微信小程序常见的配置传旨
  • (2024)docker-compose实战 (8)部署LAMP项目(最终版)
  • (7)svelte 教程: Props(属性)
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (二)Eureka服务搭建,服务注册,服务发现
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • (附源码)ssm教师工作量核算统计系统 毕业设计 162307
  • (一)SvelteKit教程:hello world
  • . NET自动找可写目录
  • ..回顾17,展望18
  • .net 前台table如何加一列下拉框_如何用Word编辑参考文献
  • .net 微服务 服务保护 自动重试 Polly