用abp vNext快速开发Quartz.NET定时任务管理界面
今天这篇文章我将通过实例代码带着大家一步一步通过abp vNext这个asp.net core的快速开发框架来进行Quartz.net定时任务调度的管理界面的开发。大伙最好跟着一起敲一下代码,当然源码我会上传到github上,有兴趣的小伙伴可以在文章底部查看源码链接。
作者:依乐祝
原文链接:https://www.cnblogs.com/yilezhu/p/10444060.html
写在前面
有几天没更新博客了,一方面因为比较忙,另一方面是因为最近在准备组织我们霸都合肥的.NET技术社区首次非正式的线下聚会,忙着联系人啊,这里欢迎有兴趣的小伙伴加我wx:jkingzhu进行详细的了解,当然也欢迎同行加我微信,然后我拉你进入我们合肥.NET技术社区微信群跟大伙进行交流。
概念
开始之前还有必要跟大伙说一下abp vNext以及Quartz.net是什么,防止有小白。如果对这两个概念非常熟悉的话可以直接阅读下一节。项目最终实现的效果如下图所示:
abp vNext是什么
说起abp vNext就要从另一个概念开始说起了,那就是大名鼎鼎的ABP了。
ABP 官方的介绍是:ASP.NET Boilerplate 是一个用最佳实践和流行技术开发现代 WEB 应用程序的新起点,它旨在成为一个通用的 WEB 应用程序基础框架和项目模板。基于 DDD 的经典分层架构思想,实现了众多 DDD 的概念(但没有实现所有 DDD 的概念)。
而ABPVNext的出现是为了抛弃掉.net framework 版本下的包袱,重新启动的 abp 框架,目的是为了放弃对传统技术的支持,让 asp.net core 能够自身做到更加的模块化,目前这块的内容还不够成熟。原因是缺少组件信息和内容。
如果你想用于生产环境建议你可以使用ABP,如果你敢于尝试,勇于创新的话可以直接使用abp vNext进行开发的。
abp vNext官网:https://abp.io/
github:https://github.com/abpframework/abp
文档:https://abp.io/documents
Quartz.NET是什么
Quartz.NET是一个强大、开源、轻量的作业调度框架,你能够用它来为执行一个作业而创建简单的或复杂的作业调度。它有很多特征,如:数据库支持,集群,插件,支持cron-like表达式等等。目前已经正式支持了.NET Core 和async/await。
说白了就是你可以使用Quartz.NET可以很方便的开发定时任务诸如平时的工作中,定时轮询数据库同步,定时邮件通知,定时处理数据等。
实例演练
这一节我们通过实例进行操作,相信跟着做的你也能够把代码跑起来。
ABP vNext代码
既然我们此次演练的项目是使用的abp vNext这个asp.net core的快速开发框架来完成的,所以首先在项目开始之前,你需要到ABP vNext的官网上去下载项目代码。英文站打开慢的话,可以访问中文子域名进行访问:https://cn.abp.io/Templates 。下面给出具体步骤:
打开https://cn.abp.io/Templates 然后如图填写对应的项目名称,这里我用的
Czar.AbpDemo
项目类型选择ASP.NET Core MVC应用程序,因为这个是带有UI界面的web项目,数据库提供程序选择EFCore这个大家都比较熟悉,然后点击创建就可以了。下载后,解压到一个文件夹下面,然后用vs打开解决方案,看到如下图所示的项目结构
这里简单介绍下,每个项目的作用,具体的就不过多介绍了,在下面的实战代码中慢慢体会吧
.Domain
为领域层..Application
为应用层..Web
为是表示层..EntityFrameworkCore
是EF Core集成.
解决方案还包含配置好的的单元&集成测试项目, 以便与于EF Core 和 SQLite 数据库配合使用.
查看
.Web
项目下appsettings.json
文件中的 连接字符串并进行相应的修改,怎么改不要问我:{
"ConnectionStrings": {
"Default": "Server=localhost;Database=CzarAbpDemo;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
右键单击
.Web
项目并将其设为启动项目打开包管理器控制台(Package Manager Console), 选择
.EntityFrameworkCore
项目作为默认项目并运行Update-Database
命令:现在可以运行应用程序,它将会打开home页面:
点击“Login” 输入用户名
admin
, 密码1q2w3E*
, 登录应用程序.启动模板包括 身份管理(identity management) 模块. 登录后将提供身份管理菜单,你可以在其中管理角色,用户及其权限. 这个不过多讲解了,自己去动手操作一番吧
集成Quartz.NET管理功能
这部分我们将实现Quartz.NET定时任务的管理功能,为了进行Quartz.NET定时任务的管理,我们还需要定义一个表来进行Quartz.NET定时任务的信息的承载,并完成这个表的增删改查功能,这样我们在对这个表的数据进行操作的同时来进行Quartz.NET定时任务的操作即可实现我们的需求。话不多说,开始吧。这部分我们再分成两个小节:JobInfo的增删改查功能的实现,Quartz.NET调度任务功能的增删改查的实现。
JobInfo的增删改查功能的实现
这个部分你将体会到我为什么使用abp vNext框架来进行开发了,就是因为快~~~~
创建领域实体对象JobInfo,这个在领域层代码如下:
将我们的JobInfo实体添加到DBContext中,这样应该在EF层
添加新的Migration并更新到数据库中,这个应该算EFCore的基础了吧,两个步骤,一个“Add-Migration” 然后“Update-Database”更新到数据库即可
Add-Migration "Add_JobInfo_Entity"
Update-Database
应用层创建页面显示实体
BookDto
用来在 基础设施层 和 应用层 传递数据同样的你还需要在应用层创建一个用来传递增改的Dto对象
万事俱备,只欠服务了,接下来我们创建一下
JobInfo
的服务接口以及服务接口的实现了,这里有个约定,就是所有的服务AppService
结尾,就跟控制器都以Controller
结尾的概念差不多。服务实现:
注释还算清真,相信你应该能看懂。
这里abp vNext框架就会自动为我们实现增删改查的API Controllers接口的实现(可以通过swagger进行查看),还会自动 为所有的API接口创建了JavaScript 代理.因此,你可以像调用 JavaScript function一样调用任何接口.
如下图所示
是不是,感觉什么都还没做,所有接口都已经实现的感觉。新增一个菜单任务调度的菜单,如下代码所示:
对应的,我们需要在
Pages/JobSchedule
这个路径下面创建对应的Index.cshtml页面,以及新增,编辑的页面。由于内容太多,这里就不贴代码了,只给大家贴下图:Index.cshtml
CreateModal.cshtml代码如下:
然后我们运行起来查看下:
点击,右上角的新增,会弹出新增界面,点击每一行的操作,会弹出删除(删除,这里只做了一个假功能),编辑的两个选项。
到此,
JobInfo
的增删改查就做好了,是不是很简单,这就是abp vNext赋予我们的高效之处。
Quartz.NET调度任务功能的增删改的实现
在使用Quartz.NET之前,你需要通过Nuget进行下安装,然后才能进行调用。这里我不会给你详细讲解Quartz.NET的使用,因为这将占用大量的篇幅,并偏离本文的主旨
安装Quartz.NET的Nuget包:
新建一个
ScheduleCenter
的任务调度中心,代码如下所示:/// <summary>
/// 任务调度中心
/// </summary>
public class ScheduleCenter
{
private readonly ILogger _logger;
public ScheduleCenter(ILogger<ScheduleCenter> logger)
{
_logger = logger;
} /// <summary>
/// 任务计划
/// </summary>
public IScheduler scheduler = null;
public async Task<IScheduler> GetSchedulerAsync()
{
if (scheduler != null)
{
return scheduler;
}
else
{
// 从Factory中获取Scheduler实例
NameValueCollection props = new NameValueCollection
{
{ "quartz.serializer.type", "binary" },
//以下配置需要数据库表配合使用,表结构sql地址:https://github.com/quartznet/quartznet/tree/master/database/tables
//{ "quartz.jobStore.type","Quartz.Impl.AdoJobStore.JobStoreTX, Quartz"},
//{ "quartz.jobStore.driverDelegateType","Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz"},
//{ "quartz.jobStore.tablePrefix","QRTZ_"},
//{ "quartz.jobStore.dataSource","myDS"},
//{ "quartz.dataSource.myDS.connectionString",AppSettingHelper.MysqlConnection},//连接字符串
//{ "quartz.dataSource.myDS.provider","MySql"},
//{ "quartz.jobStore.usePropert ies","true"} };
StdSchedulerFactory factory = new StdSchedulerFactory(props);
return await factory.GetScheduler(); }
} /// <summary>
/// 添加调度任务
/// </summary>
/// <param name="jobName">任务名称</param>
/// <param name="jobGroup">任务分组</param>
/// <returns></returns>
public async Task<bool> AddJobAsync(CreateUpdateJobInfoDto infoDto)
{
try
{
if (infoDto!=null)
{
if (infoDto.StarTime == null)
{
infoDto.StarTime = DateTime.Now;
}
DateTimeOffset starRunTime = DateBuilder.NextGivenSecondDate(infoDto.StarTime, 1);
if (infoDto.EndTime == null)
{
infoDto.EndTime = DateTime.MaxValue.AddDays(-1);
}
DateTimeOffset endRunTime = DateBuilder.NextGivenSecondDate(infoDto.EndTime, 1);
scheduler = await GetSchedulerAsync();
JobKey jobKey = new JobKey(infoDto.JobName, infoDto.JobGroup);
if (await scheduler.CheckExists(jobKey))
{
await scheduler.PauseJob(jobKey);
await scheduler.DeleteJob(jobKey);
}
IJobDetail job = JobBuilder.Create<LogTestJob>()
.WithIdentity(jobKey)
.Build();
ICronTrigger trigger = (ICronTrigger)TriggerBuilder.Create()
.StartAt(starRunTime)
.EndAt(endRunTime)
.WithIdentity(infoDto.JobName, infoDto.JobGroup)
.WithCronSchedule(infoDto.CronExpress)
.Build();
await scheduler.ScheduleJob(job, trigger);
await scheduler.Start();
return true;
} return false;//JobInfo为空
}
catch (Exception ex)
{
_logger.LogException(ex);
return false;//出现异常
}
} /// <summary>
/// 暂停指定任务计划
/// </summary>
/// <param name="jobName">任务名</param>
/// <param name="jobGroup">任务分组</param>
/// <returns></returns>
public async Task<bool> StopJobAsync(string jobName, string jobGroup)
{
try
{
JobKey jobKey = new JobKey(jobName, jobGroup);
scheduler = await GetSchedulerAsync();
if (await scheduler.CheckExists(jobKey))
{
await scheduler.PauseJob(new JobKey(jobName, jobGroup));
return true;
}
else
{
return false;//任务不存在
}
}
catch (Exception ex)
{
_logger.LogException(ex);
return false;//出现异常
}
} /// <summary>
/// 恢复指定的任务计划,如果是程序奔溃后 或者是进程杀死后的恢复,此方法无效
/// </summary>
/// <param name="jobName">任务名称</param>
/// <param name="jobGroup">任务组</param>
/// <returns></returns>
public async Task<bool> ResumeJobAsync(string jobName, string jobGroup)
{
try
{
JobKey jobKey = new JobKey(jobName, jobGroup);
scheduler = await GetSchedulerAsync();
if (await scheduler.CheckExists(jobKey))
{
//resumejob 恢复
await scheduler.ResumeJob(new JobKey(jobName, jobGroup));
return true;
}
else
{
return false;//不存在任务
} }
catch (Exception ex)
{
_logger.LogException(ex);
return false;//出现异常
}
} /// <summary>
/// 恢复指定的任务计划,如果是程序奔溃后 或者是进程杀死后的恢复,此方法无效
/// </summary>
/// <param name="jobName">任务名称</param>
/// <param name="jobGroup">任务组</param>
/// <returns></returns>
public async Task<bool> DeleteJobAsync(string jobName, string jobGroup)
{
try
{
JobKey jobKey = new JobKey(jobName, jobGroup);
scheduler = await GetSchedulerAsync();
if (await scheduler.CheckExists(jobKey))
{
//DeleteJob 恢复
await scheduler.DeleteJob(jobKey);
return true;
}
else
{
return false;//不存在任务
} }
catch (Exception ex)
{
_logger.LogException(ex);
return false;//出现异常
}
}
}
新建一个
LogTestJob
的计划任务,代码如下所示,需要继承IJob
接口:至此Quartz.NET调度任务功能完成
集成
这里我们按照之前的思路对JobInfo
跟Quartz.NET任务进行集成
新增时,启动任务:
编辑时,更新任务
这里细心的网友,可能注意到任务的删除是在编辑里面进行实现的。而列表页面的删除功能并没有实现真正意义的功能的删除。
功能演示
上面我们演示的任务是一个每5秒写入当前时间的一个任务,并实现了对这个任务的新增,删除,编辑的功能,这里大伙可以自行实现进行测试,也可以下载我的代码进行尝试。效果图如下所示:
功能扩展
目前只能对既定义好任务进行调度,后期可以根据任务的名称,如我们实例中的测试任务LogTestJob
的名字找到这个任务,然后动态的进行处理。这样就可以在界面实现对多个任务进行调度了!当然还有其他的扩展,本文只是作为引子。
源码地址
GitHub:https://github.com/yilezhu/AbpQuzatzDemo
总结
本文只是简单的利用abp vNext框架进行Quartz.NET任务调度进行UI的管理,实现的功能也比较简单,大家完全可以在此基础上进行扩展完善,最后感谢大伙的阅读。
用abp vNext快速开发Quartz.NET定时任务管理界面的更多相关文章
- macOS使用ABP.vNext Core开发CMS系统(一) 让程序跑起来
macOS使用ABP.vNext Core开发CMS系统(一) 让程序跑起来--2020年10月5日 国庆假期,陪老婆的同时也不能忘记给自己充充电,这不想搞个CMS系统,考虑自己的时间并不多,所以想找 ...
- 尝试从零开始构建我的商城 (一) :使用Abp vNext快速一个简单的商城项目
尝试从零开始构建我的商城 (一) :使用Abp vNext快速搭建一个简单的项目 前言 GitHub地址 https://github.com/yingpanwang/MyShop 此文目的 本文将尝 ...
- 网站迁移纪实:从Web Form 到 Asp.Net Core (Abp vNext 自定义开发)
问题和需求 从2004年上线,ZLDNN.COM运行已经超过16年了,一直使用DotNetNuke平台(现在叫DNN Platform),从最初的DotNetNuke 2.1到现在使用的7.4.先是在 ...
- SNF快速开发平台3.0之-界面个性化配置+10种皮肤+7种菜单-Asp.net+MVC4.0+WebAPI+EasyUI+Knockout
一.个性配置-首页:可以进行拖动保存配置,下次登录时就会按配置的进行加载 二.个人配置页面 7种菜单用户可自定义配置,和预览效果 10种皮肤自定义配置,和预览效果 皮肤和菜单可以随意组合-部分截图: ...
- SpringBoot2.x集成Quartz实现定时任务管理(持久化到数据库)
1. Quartz简介 Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目. Quartz是一个完全由Java编写的开源作业调度框架,为在Java应 ...
- 审核流(3)低调奢华,简单不凡,实例演示-SNF.WorkFlow--SNF快速开发平台3.1
下面我们就从什么都没有,结合审核流进行演示实例.从无到有如何快速完美的实现,然而如此简单.低调而奢华,简单而不凡. 从只有数据表通过SNF.CodeGenerator代码生成器快速生成单据并与审核流进 ...
- 审核流(2)流程设计-SNF.WorkFlow功能使用说明--SNF快速开发平台3.1
流程设计 图形化的流程设计,更方便.直观 1.打开“流程设计“程序,如上.点击”新建“如下: 2.红色部分为必填项,审批对象是选择要审批的程序菜单,单据名称是在审核流流转时用于提示的单据名称,还要选择 ...
- SNF开发平台WinForm之十四-站内发送系统信息-SNF快速开发平台3.3-Spring.Net.Framework
1运行效果: 2开发实现: .组装站内信息发送实体对象. SNFService SNFService = new SNFService(); if (this.ucUser.SelectedIds ! ...
- SNF开发平台WinForm之十三-单独从服务器上获取PDF文件进行显示-SNF快速开发平台3.3-Spring.Net.Framework
1运行效果: 2开发实现: 如果需要单独显示PDF文件时用下面代码去实现,指定url地址. 地址: . 获取附件管理的实体对象: List<KeyValuePair<string, obj ...
随机推荐
- JMeter调试参数是否取值正确,调试正则提取的结果(log.info|log.error|print)
JMeter调试参数是否取值正确,调试正则提取的结果(log.info | log.error | print) Jmeter的log输出控制(jmeter.log) 1 2 log_level.jm ...
- A - A Secret -扩展KMP
题目大意: 给你两个字符串A,B,现在要你求B串的后缀在A串中出现的次数和后缀长度的乘积和为多少. 题解: 扩展KMP模板题,将A和B串都逆序以后就变成了求前缀的问题了,扩展KMP求处从i位置开始的最 ...
- 五、OpenStack—nova组件介绍与安装
一.nova介绍 Nova 是 OpenStack 最核心的服务,负责维护和管理云环境的计算资源.OpenStack 作为 IaaS 的云操作系统,虚拟机生命周期管理也就是通过 Nova 来实现的. ...
- Shell脚本学习 - 基本内容以及数据格式
为了捞取日志,自己用python写了一些东西,大致套路就是读取写入文件的操作,放到linux上跑.实际使用时发现要操作的文件有时比较大,直接打开文件找需要的东西可能会有一些效率问题.所以学习一下she ...
- JAVA基础复习与总结<四> 抽象类与接口
抽象类(Abstract Class) 是一种模版模式.抽象类为所有子类提供了一个通用模版,子类可以在这个模版基础上进行扩展.通过抽象类,可以避免子类设计的随意性.通过抽象类,我们就可以做到严格限制子 ...
- [Python]CentOS - ImportError: No module named '_curses'
网上搜了不少答案, 基本都是说Windows环境下curses包不适用的问题. 作为碰到这个问题的linux用户,实在感到无奈. 起因是在CentOS上部署uwsgi,想要使用uwsgitop来监控. ...
- selenium3 调用IE Unable to get browser
本地环境开发,移至服务器上出现Unable to get browser的问题.经过查找找到问题所在(第六点,需要修改注册表增加键): 1.下载IEDriverServer.进入索引页,首先选择版本号 ...
- slitaz的root密码
可以先试试root(我这个版本就是),如果不行passwd改密码吧...
- nodejs编译遇到的问题
src\node_contextify.cc:631: Assertion 'args[1]->IsString()' failed. node 10 版本会出现这个问题, 安装natives后 ...
- iOS逆向工程概述(转)
逆向工程一词,对很多人来说可能很陌生,在android领域,我们经常会听到“反编译某个apk”,那么逆向工程从某种角度讲也包括反编译这项技术,这样一对比,可能我们就更容易理解逆向工程的定义了. 我们引 ...