Uwl.Admin开源框架(二)
Uwl.Admin.Core中使用QuartzNet定时任务模块:
本文负责讲解RabbitMQ的使用
Uwl.Admin.Core使用的技术有:
*、Async和Await 异步编程
*、Repository + Service 仓储模式编程;仓储模式支持工作单元
*、Swagger 前后端文档说明,基于RESTful风格编写接口
*、Cors 简单的跨域解决方案
*、JWT自定义策略授权权限验证
*、依赖注入选择的是官方自带的DI注入,没有使用第三方框架,ORM使用EF Core,数据库使用的是Sql server,(后期会扩展MySql版本);
*、AutoMapper 自动对象映射、
*、Linq To Sql \ lambda表达式树查询;(表达式树查询是个人扩展的,表达式树的使用方法请参考Uwl.Data.Server.MenuServer的多条件查询)
*、登录认证方式使用JWT认证方式,后台接口使用SwaggerUI展示,角色权限使用 自定义权限处理器PermissionHandler 继承与微软官方 IAuthorizationRequirement;
*、Excel导入导出使用的是Epplus第三方框架,导入导出只需要配置Attribute特性就好,不需要在自己写列名;导出只支持List导出,暂时不支持Datatable;(Excel使用方法请参考UserController控制器)
*、Rabbit MQ消息队列(目前暂无业务使用场景后期准备用来记录日志)
*、Redis 轻量级分布式缓存;(Redis使用方法请参考Uwl.Data.Server.MenuServer类)
*、QuartzNet第三方任务框架;(使用方法请参考类库Uwl.ScheduledTask.Job.TestJobOne类)
*、IdentityServer4授权模式已开发完成,未发布演示服务器代码在github;(Identityserver4Auth分支)
Quartz.NET:
Quartz.NET官网地址:https://www.quartz-scheduler.net/
Quartz.NET文档地址:https://www.quartz-scheduler.net/documentation/index.html
Quartz.NET
是一个开源的作业调度框架,是OpenSymphony
的 Quartz API
的.NET移植,它用C#写成,可用于winform
和asp.net
应用中。它提供了巨大的灵活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,支持cron-like
表达式等等。
现在Quartz.NET3.0
已支持Asp.Net Core
,3.0新功能如下:
新功能
- 具有异步/等待支持的基于任务的作业,内部以异步/等待方式工作
- 支持.NET Core / netstandard 2.0和.NET Framework 4.5.2及更高版本
- 通过提供程序名称
SQLite-Microsoft
支持Microsoft.Data.Sqlite
,旧的提供程序SQLite
也仍然有效 - 增加了
SQL Server
内存优化表和Quartz.Impl.AdoJobStore.UpdateLockRowSemaphoreMOT
的初步支持 Common.Logging
从相关性中删除- 从
ILMerge
进程中删除的C5集合不再需要 - 在插件启动时添加对作业调度XML文件的急切验证的支持
- 在
TimeZoneUtil
中添加对额外的自定义时区解析器功能的支持
变化
- 作业和插件现在位于独立的程序集
NuGet
包Quartz.Jobs
和Quartz.Plugins
中 - ADO.NET提供者名称已被简化,提供者名称没有版本,例如
SqlServer-20 => SqlServer
- API方法已被重新使用,主要使用
IReadOnlyCollection
,这隐藏了两个HashSet
s和List小号 LibLog
一直隐藏于内部(ILog等),就像它原本打算的那样SimpleThreadPool
消失了,旧的拥有的线程消失了- 调度程序方法已更改为基于任务,请记住等待它们
IJob
接口现在返回一个任务- 一些
IList
属性已更改为IReadOnlyList
以正确反映意图 SQL Server CE
支持已被删除DailyCalendar
现在将日期时间用于排除的日期,并具有ISet
接口来访问它们IObjectSerializer
有新的方法,void Initialize()
,必须实现IInterruptableJob
取消了上下文的CancellationToken
Quartz API的关键接口和类是:
IScheduler
- 与调度程序交互的主要API。IJob
- 您希望由调度程序执行的组件实现的接口。IJobDetail
- 用于定义作业的实例。ITrigger
- 定义执行给定Job的时间表的组件。JobBuilder
- 用于定义/构建定义作业实例的JobDetail
实例。TriggerBuilder
- 用于定义/构建触发器实例
一、Quartz.NET基本使用
1、新建Uwl.QuartzNet.JobCenter 类库项目,使用NuGet添加Quartz,或使用程序包管理器引用,命令如下:
Install-Package Quartz
2、Uwl.QuartzNet.JobCenter 类库的作用:
Uwl.QuartzNet.JobCenter 类库是计划任务管理中心,这里我就放一段代码了,不放太多,具体的实现可以下载下来Uwl.Admin.Core项目看
/// <summary>
/// 开启任务调度
/// </summary>
/// <returns></returns>
public async Task<JobResuleModel> StartScheduleAsync()
{
var result = new JobResuleModel();
try
{
if (!this._scheduler.Result.IsStarted)
{
//等待任务运行完成
await this._scheduler.Result.Start();
await Console.Out.WriteLineAsync("任务调度开启!");
result.IsSuccess = true;
result.Message = $"任务调度开启成功";
return result;
}
else
{
result.IsSuccess = false;
result.Message = $"任务调度已经开启";
return result;
}
}
catch (Exception)
{
throw;
}
}
如果你想添加JSON序列化,只需要以同样的方式添加Quartz.Serialization.Json
包。
2、简单实例,代码如下:
using Five.QuartzNetJob.ExecuteJobTask.Service;
using Quartz;
using Quartz.Impl;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Threading.Tasks; namespace Five.QuartzNetJob.Web.Controllers
{
public class TestTask
{
public async Task StartTestAsync()
{
try
{
// 从工厂中获取调度程序实例
NameValueCollection props = new NameValueCollection
{
{ "quartz.serializer.type", "binary" }
};
StdSchedulerFactory factory = new StdSchedulerFactory(props);
IScheduler scheduler = await factory.GetScheduler(); // 开启调度器
await scheduler.Start(); // 定义这个工作,并将其绑定到我们的IJob实现类
IJobDetail job = JobBuilder.Create<HelloJob>()
.WithIdentity("job1", "group1")
.Build(); // 触发作业立即运行,然后每10秒重复一次,无限循环
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "group1")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(10)
.RepeatForever())
.Build(); // 告诉Quartz使用我们的触发器来安排作业
await scheduler.ScheduleJob(job, trigger); // 等待60秒
await Task.Delay(TimeSpan.FromSeconds(60)); // 关闭调度程序
await scheduler.Shutdown();
}
catch (SchedulerException se)
{
await Console.Error.WriteLineAsync(se.ToString());
}
}
}
}
TestJobOne内容如下:
using Quartz;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Uwl.Common.Cache.RedisCache;
using Uwl.Common.Subscription;
using Uwl.Data.Server.MenuServices; namespace Uwl.ScheduledTask.Job
{
public class TestJobOne : IJob
{
private readonly IRedisCacheManager _redisCacheManager;
private readonly IMenuServer _menuServer;
public TestJobOne(IRedisCacheManager redisCacheManager,IMenuServer menuServer)
{
this._redisCacheManager = redisCacheManager;
this._menuServer = menuServer;
}
public async Task Execute(IJobExecutionContext context)
{
//记录Job时间
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
await Console.Out.WriteLineAsync("我是有Redis的注入测试任务");
var list = await _menuServer.GetMenuList();
await Console.Out.WriteLineAsync("菜单表里总数量" + list.Count.ToString());
stopwatch.Stop();
await Console.Out.WriteLineAsync("执行时间" + stopwatch.Elapsed.TotalMilliseconds);
//if (stopwatch.Elapsed.TotalMilliseconds > 0)
//{
// //写入日志性能监控表和执行是否出错
//}
}
}
}
执行效果:
二、触发器类型
1、SimpleTrigger触发器(简单触发器)
SimpleTrigger
的属性包括:开始时间和结束时间,重复计数和重复间隔。重复计数可以是零,一个正整数或常数值SimpleTrigger.RepeatIndefinitely
。重复时间间隔属性必须是TimeSpan.Zero
或正的TimeSpan
值。请注意,重复间隔为0会导致触发器的“重复计数”触发同时发生。SimpleTrigger
实例使用TriggerBuilder
(用于触发器的主属性)和WithSimpleSchedule
扩展方法(用于SimpleTrigger
特定的属性)构建。
在特定的时间内建立触发器,无需重复,代码如下:
/// <summary>
/// 创建SimpleTrigger触发器(简单触发器)
/// </summary>
/// <param name="sysSchedule"></param>
/// <param name="starRunTime"></param>
/// <param name="endRunTime"></param>
/// <returns></returns>
private ITrigger CreateSimpleTrigger(SysSchedule sysSchedule)
{
if(sysSchedule.RunTimes>0)
{
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity(sysSchedule.Id.ToString(), sysSchedule.JobGroup)
.StartAt(sysSchedule.BeginTime.Value)
.EndAt(sysSchedule.EndTime.Value)
.WithSimpleSchedule(x =>
x.WithIntervalInSeconds(sysSchedule.IntervalSecond)
.WithRepeatCount(sysSchedule.RunTimes)).ForJob(sysSchedule.Id.ToString(), sysSchedule.JobGroup).Build();
return trigger;
}
else
{
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity(sysSchedule.Id.ToString(), sysSchedule.JobGroup)
.StartAt(sysSchedule.BeginTime.Value)
.EndAt(sysSchedule.EndTime.Value)
.WithSimpleSchedule(x =>
x.WithIntervalInSeconds(sysSchedule.IntervalSecond)
.RepeatForever()).ForJob(sysSchedule.Id.ToString(), sysSchedule.JobGroup).Build();
return trigger;
}
// 触发作业立即运行,然后每10秒重复一次,无限循环
}
因此简单的任务调度使用SimpleTrigger
完全够用,如果SimpleTrigger
还是不能满足您的需求请往下看。
2、CronTrigger触发器
如果你需要一个基于类似日历的概念而不是精确指定的SimpleTrigger
时间间隔的工作调度计划,CronTriggers
通常比SimpleTrigger
更有用。
使用CronTrigger
,您可以在每周一,周三的上午9点至上午10点之间指定开始时间表,例如“每星期五中午”或“每个工作日和上午9点30分”,或者“每5分钟”和星期五”。
即使如此,就像SimpleTrigger
一样,CronTrigger
有一个startTime
,它指定了时间表的生效时间,还有一个(可选的)endTime
,用于指定应该停止时间表的时间。
这里不在详细介绍Cron
。
Cron表达式在线生成器:http://cron.qqe2.com/
Cron表达式详细介绍:https://www.jianshu.com/p/e9ce1a7e1ed1
/// <summary>
/// 创建类型Cron的触发器
/// </summary>
/// <param name="m"></param>
/// <returns></returns>
private ITrigger CreateCronTrigger(SysSchedule sysSchedule)
{
// 作业触发器
return TriggerBuilder.Create()
.WithIdentity(sysSchedule.Id.ToString(), sysSchedule.JobGroup)
.StartAt(sysSchedule.BeginTime.Value)//开始时间
.EndAt(sysSchedule.EndTime.Value)//结束数据
.WithCronSchedule(sysSchedule.Cron)//指定cron表达式
.ForJob(sysSchedule.Id.ToString(), sysSchedule.JobGroup)//作业名称
.Build();
}
三、在Uwl.Admin.Core配置使用方法
1、在Uwl.ScheduledTask.Job类库下面新建一个类继承于JobBase和IJob接口:
2、在新建的类里面写一个方法,并且把这个方法通过实现的IJob的Execute方法传给JobBase基类:
3、在新建的类里面写一个方法,并且把这个方法通过实现的IJob的Execute方法传给JobBase基类:
在uwl.admin后台管理的定时任务模块添加一个新的任务,填写对应的名称,这里需要注意的是(DLL程序集是☞你的类库,任务所在类是指你的Job需要执行的Calss,这里有两种触发类型,一个是simple类型,一个是Cron类型可以根据自己的需要去设置对应的类型
simple类型适合简单任务,开始时间和结束时间非必填,不填的话在你点击开始任务的时候就是默认执行,结束时间取的是最大时间)
为什么要填程序集和类的名字呢,因为这里我是通过反射来获取程序集和类来进行执行那个Job的
我们把这些配置完成之后点击启动任务就OK啦~~
这里还有一点小问题……就是程序暂停运行了之后不会自动启动在执行的任务,后面我会慢慢修复,暂且各位大佬每次发布之后记得点击一下启动任务嗷~~~
总结(很重要): Quartz.NET
的3.0版本跟之前的版本api接口变化并不大。只是在3.0.7版本中添加了异步调用,并支持.net core。简单的任务调度使用官网中的实例即可满足需求,进行依赖注入的时候应当重写IJobFactory工厂,在IJobFactory工厂内重写 NewJob,ReturnJob方法;
具体代码实现
/// <summary>
/// 注入反射获取依赖对象
/// </summary>
private readonly IServiceProvider _serviceProvider;
public IOCJobFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
/// <summary>
/// 实现接口Job
/// </summary>
/// <param name="bundle"></param>
/// <param name="scheduler"></param>
/// <returns></returns>
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
try
{
这个位置需要重新创建_serviceProvider.CreateScope();容器,不然会提示找不到Job/还有一种情况是你也注入了但是Job无法执行,所以这个位置应当重新创建容器实例,
var serviceScope = _serviceProvider.CreateScope();
var job = serviceScope.ServiceProvider.GetService(bundle.JobDetail.JobType) as IJob;
return job;
//var job = _serviceProvider.GetService(bundle.JobDetail.JobType) as IJob;
//return job;
}
catch (Exception e)
{
throw e;
}
}
public void ReturnJob(IJob job)
{
var disposable = job as IDisposable;
if(disposable!=null)
{
disposable.Dispose();
}
}
Uwl.Admin开源框架(二)的更多相关文章
- Uwl.Admin开源框架(一)
1.前言 作为一个忠实的软粉,一直期待微软出跨平台,一直在等待.Net Core,因为刚毕业对于.Net的很多东西不是很熟知,就开始了.Net Core的摸索,一路上坎坎坷坷,对于新技术一直很期待,就 ...
- ERP开源框架 + 二次开发平台 介绍
经历了多年软件开发,深受网络大侠们的资源共享才得以有所成绩, 本人主要是做企业ERP软件,一直有个感受,开发具体某个功能不难,但随着需求的增加,管理庞大的代码却成了最大的问题 而为企业管理所做的开发, ...
- Uwl.Admin.Core开源框架(二) 使用QuartzNet
Uwl.Admin.Core中使用QuartzNet定时任务模块: 本文负责讲解RabbitMQ的使用 Uwl.Admin.Core使用的技术有: *.Async和Await 异步编程 *.Repos ...
- Uwl.Admin.Core开源框架(三) 使用RabbitMQ
Uwl.Admin.Core中使用RabbitMQ消息队列: 本文负责讲解RabbitMQ的使用 Uwl.Admin.Core使用的技术有: *.Async和Await 异步编程 *.Reposito ...
- Magicodes.Admin.Core开源框架总体介绍
框架说明 Magicodes.Admin.Core框架在ABP以及ASP.NET ZERO的基础上进行了封装和完善,目前基于.NET Core 2.0+(Framework版本),由于部分组件在.NE ...
- Android 开源框架Universal-Image-Loader完全解析(二)--- 图片缓存策略详解
转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/26810303),请尊重他人的辛勤劳动成果,谢谢! 本篇文章 ...
- Android 开源框架Universal-Image-Loader全然解析(二)--- 图片缓存策略具体解释
转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/26810303),请尊重他人的辛勤劳动成果,谢谢! 本篇文章 ...
- 开源框架.netCore DncZeus学习(二)配置连接
配置连接字符串,update-database,初始数据后,访问报错,提示offset错误.因为本机上使用的sql2008. .net Core 2.X中的EF访问sqlserver2008默认使用的 ...
- Pyhton开源框架(加强版)
info:Djangourl:https://www.oschina.net/p/djangodetail: Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC)风格的 ...
随机推荐
- Windows 操作系统 端口转发
在Windows 下可以使用netsh interface portproxy 命令实现端口转发功能. 例:netsh interface portproxy add v4tov4 listenpor ...
- 算法习题---4-6莫尔斯电码(UVa508)
一:题目 A-Z0-9分别对应一些莫尔斯电码字符串 A .- B -... C -.-. D -.. E . F ..-. G --. H .... I .. J .--- K -.- L .-.. ...
- 浅谈-对modbus的理解
浅谈-对modbus的理解 一.简介 Modbus由MODICON公司于1979年开发,是一种工业现场总线协议标准.1996年施耐德公司推出基于以太网TCP/IP的Modbus协议:ModbusTCP ...
- Ubuntu 16.04 haproxy 简单配置应用
HAproxy HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性.负载均衡,以及基于TCP和HTTP的应用程序代理. 测试环境 ubuntu16.04 192.168.20 ...
- C# http请求 设置代理(标题可以作为搜索关键字)
例一(C# 通过代理发HTTP请求): https://q.cnblogs.com/q/88682/ 例二(C# 代理HTTP请求): https://www.cnblogs.com/ShalenCh ...
- 给 textbox TextMode="password" 赋值后显示出来
在做一个修改用户资料的页面的时候,发现用 <asp:TextBox ID="txtPwd" runat="server" TextMode="P ...
- iOS使用UIImageView展现网络图片(转载)
在iOS开发过程中,经常会遇到使用UIImageView展现来自网络的图片的情况,最简单的做法如下: [cpp] view plaincopy - (void)viewDidLoad { [sup ...
- 成为java架构师的技能
0: 数据结构算法 数组.链表.堆.栈.队列.Hash表.二叉树等; 算法思想:递推.递归.穷举.贪心.分治.动态规划.迭代.分枝界限; 排序查找 B+/B-数.红黑树.图等; 图的深度优先搜索.图的 ...
- 微信小程序获取windowHeight出现不同页面高度不一致问题及解决方案
在页面中调用wx.getSystemInfo即可获取当前页面的屏幕高度,如果写在app.js里面或者带有系统tab页面里面,获取的windowHeight会比不是tab的页面少48: 含有的TabBa ...
- STL源码剖析-学习笔记
1.模板是一个公式或是蓝图,本身不是类或是函数,需进行实例化的过程.这个过程是在编译期完成的,编译器根据传递的实参,推断出形参的类型,从而实例化相应的函数 2. 后续补充-.