Asp.Net Core 使用Quartz基于界面画接口管理做定时任务
今天抽出一点点时间来造一个小轮子,是关于定时任务这块的。
这篇文章主要从一下几点介绍:
- 创建数据库管理表
- 创建web项目
- 引入quarzt nuget 包
- 写具体配置操作,实现定时任务处理
第一步:创建一个空web项目,引入quarzt nuget 包

创建TB.AspNetCore.Quartz web项目和TB.AspNetCore.Data 类库,在web项目中引入Quartz nuget包
第二部:数据库创建一张管理表

-- ----------------------------
-- Table structure for ScheduleInfo
-- ----------------------------
DROP TABLE IF EXISTS `ScheduleInfo`;
CREATE TABLE `ScheduleInfo` (
`Id` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
`JobGroup` varchar(100) NOT NULL DEFAULT '' COMMENT '任务组',
`JobName` varchar(50) NOT NULL DEFAULT '' COMMENT '任务名',
`RunStatus` int(11) NOT NULL DEFAULT '' COMMENT '运行状态',
`CromExpress` varchar(40) NOT NULL DEFAULT '' COMMENT 'Crom表达式',
`StarRunTime` datetime DEFAULT NULL COMMENT '开始运行时间',
`EndRunTime` datetime DEFAULT NULL COMMENT '结束运行时间',
`NextRunTime` datetime DEFAULT NULL COMMENT '下次运行时间',
`Token` varchar(40) NOT NULL DEFAULT '' COMMENT 'Token',
`AppID` varchar(40) NOT NULL DEFAULT '' COMMENT 'AppID',
`ServiceCode` varchar(40) DEFAULT NULL,
`InterfaceCode` varchar(40) DEFAULT NULL,
`TaskDescription` varchar(200) DEFAULT NULL,
`DataStatus` int(11) DEFAULT NULL COMMENT '数据状态',
`CreateAuthr` varchar(30) DEFAULT NULL COMMENT '创建人',
`CreateTime` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
创建数据库的表结构如图所示,接下来我们在Data项目里添加mysql数据库驱动nuget包


打开PM,执行数据库反向工程命令,从数据库生成model实体
Scaffold-DbContext "Server=你的服务器地址;Database=你的数据库;User=数据库用户名;Password=你的数据库密码;" "Pomelo.EntityFrameworkCore.MySql" -OutputDir Entity**2.1.1 建议不要选用,防坑!

将链接字符串换成你自己的,我们又新添加了一个service文件夹和一个Enum文件夹

其中,BaseService 里封装了针对数据操作的基本crud,quartz里封装了关于定时任务的配置,enum里枚举了任务状态,具体代码如下
public enum JobStatus
{
[Description("已启用")]
已启用,
[Description("运行中")]
待运行,
[Description("执行中")]
执行中,
[Description("执行完成")]
执行完成,
[Description("执行任务计划中")]
执行任务计划中,
[Description("已停止")]
已停止,
}
下面是baseservice里具体方法
public class BaseService
{
protected static object obj = new object();
public ggb_offlinebetaContext _context;
protected ggb_offlinebetaContext DataContext
{
get
{
if (_context == null)
{
_context = new ggb_offlinebetaContext();
}
return _context;
}
} public BaseService()
{ } #region 封装基crud
/// <summary>
/// 只能是唯一记录 多记录引发异常
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="predicate"></param>
/// <returns></returns>
public TSource Single<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class
{
if (predicate == null)
{
return this.DataContext.Set<TSource>().SingleOrDefault();
} return this.DataContext.Set<TSource>().SingleOrDefault(predicate);
}
/// <summary>
/// 查询一条记录
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="predicate"></param>
/// <returns></returns>
public TSource First<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class
{
if (predicate == null)
{
return this.DataContext.Set<TSource>().FirstOrDefault();
}
return this.DataContext.Set<TSource>().FirstOrDefault(predicate);
} /// <summary>
/// where条件查询
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="predicate"></param>
/// <returns></returns>
public IQueryable<TSource> Where<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class
{
if (predicate == null)
{
return this.DataContext.Set<TSource>().AsQueryable();
}
return this.DataContext.Set<TSource>().Where(predicate);
} /// <summary>
/// 记录数
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="predicate"></param>
/// <returns></returns>
public int Count<TSource>(Expression<Func<TSource, bool>> predicate = null)
where TSource : class
{
if (predicate == null)
{
return this.DataContext.Set<TSource>().Count();
}
return this.DataContext.Set<TSource>().Count(predicate);
} /// <summary>
/// 根据条件判断记录是否存在
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="predicate"></param>
/// <returns></returns>
/// Any确定序列是否包含任何元素
public bool Exists<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class
{
if (predicate == null)
{
return this.DataContext.Set<TSource>().Any();
}
return this.DataContext.Set<TSource>().Any(predicate);
} /// <summary>
/// 查询全部
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <returns></returns>
public IQueryable<TSource> Query<TSource>()
where TSource : class
{
return this.DataContext.Set<TSource>();
} /// <summary>
/// paging the query 分页查询
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="query"></param>
/// <param name="pageIndex">page index</param>
/// <param name="pageSize">page size </param>
/// <param name="count">total row record count</param>
/// <returns></returns>
public IQueryable<T> Pages<T>(IQueryable<T> query, int pageIndex, int pageSize, out int count) where T : class
{
if (pageIndex < )
{
pageIndex = ;
}
if (pageSize < )
{
pageSize = ;
}
count = query.Count();
query = query.Skip((pageIndex - ) * pageSize).Take(pageSize);
return query;
} /// <summary>
/// 分页查询
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <param name="count"></param>
/// <returns></returns>
public IQueryable<T> Pages<T>(int pageIndex, int pageSize, out int count) where T : class
{
if (pageIndex < )
{
pageIndex = ;
}
if (pageSize < )
{
pageSize = ;
}
var query = this.DataContext.Set<T>().AsQueryable();
count = query.Count();
query = query.Skip((pageIndex - ) * pageSize).Take(pageSize);
return query;
}
#endregion /// <summary>
/// 做一次提交
/// </summary>
#region Save Changes
public void Save()
{
//todo 需要验证是否需要释放
using (this.DataContext)
{
this.DataContext.SaveChanges();
}
} /// <summary>
/// 添加
/// </summary>
/// <param name="entity"></param>
/// <param name="save"></param>
public void Add(object entity, bool save = false)
{
this.DataContext.Add(entity);
if (save)
{
this.Save();
}
} /// <summary>
/// 更新实体
/// </summary>
/// <param name="entity"></param>
/// <param name="save"></param>
public void Update(object entity, bool save = false)
{
this.DataContext.Update(entity);
if (save)
{
this.Save();
}
}
/// <summary>
/// 更新2
/// </summary>
/// <param name="list"></param>
/// <param name="save"></param>
public void Update(IEnumerable<object> list, bool save = false)
{
this.DataContext.UpdateRange(list);
if (save)
{
this.Save();
}
}
/// <summary>
/// 删除1
/// </summary>
/// <param name="entity"></param>
/// <param name="save"></param>
public void Delete(object entity, bool save = false)
{
this.DataContext.Remove(entity);
if (save)
{
this.Save();
}
}
/// <summary>
/// 删除2
/// </summary>
/// <param name="list"></param>
/// <param name="save"></param>
public void Delete(IEnumerable<object> list, bool save = false)
{
this.DataContext.RemoveRange(list);
if (save)
{
this.Save();
}
}
#endregion ///// <summary>
///// 释放资源
///// </summary>
//public void Dispose()
//{
// _context.Dispose();
//}
}
下面是任务调度中心代码
/// <summary>
/// 任务调度中心
/// </summary>
public class JobCenter
{
/// <summary>
/// 任务计划
/// </summary>
public static IScheduler scheduler = null;
public static async Task<IScheduler> GetSchedulerAsync()
{
if (scheduler != null)
{
return scheduler;
}
else
{
ISchedulerFactory schedf = new StdSchedulerFactory();
IScheduler sched = await schedf.GetScheduler();
return sched;
}
}
/// <summary>
/// 添加任务计划//或者进程终止后的开启
/// </summary>
/// <returns></returns>
public async Task<bool> AddScheduleJobAsync(ScheduleInfo m)
{
try
{
if (m != null)
{
if (m.StarRunTime == null)
{
m.StarRunTime = DateTime.Now;
}
DateTimeOffset starRunTime = DateBuilder.NextGivenSecondDate(m.StarRunTime, );
if (m.EndRunTime == null)
{
m.EndRunTime = DateTime.MaxValue.AddDays(-);
}
DateTimeOffset endRunTime = DateBuilder.NextGivenSecondDate(m.EndRunTime, );
scheduler = await GetSchedulerAsync();
IJobDetail job = JobBuilder.Create<HttpJob>()
.WithIdentity(m.JobName, m.JobGroup)
.Build();
ICronTrigger trigger = (ICronTrigger)TriggerBuilder.Create()
.StartAt(starRunTime)
.EndAt(endRunTime)
.WithIdentity(m.JobName, m.JobGroup)
.WithCronSchedule(m.CromExpress)
.Build();
//将信息写入
new ScheduleManage().AddSchedule(m);
await scheduler.ScheduleJob(job, trigger);
await scheduler.Start();
await StopScheduleJobAsync(m.JobGroup, m.JobName);
return true;
}
return false;
}
catch (Exception ex)
{
//MyLogger.WriteError(ex, null);
return false;
}
} /// <summary>
/// 暂停指定任务计划
/// </summary>
/// <returns></returns>
public async Task<string> StopScheduleJobAsync(string jobGroup, string jobName)
{
try
{
scheduler = await GetSchedulerAsync();
//使任务暂停
await scheduler.PauseJob(new JobKey(jobName, jobGroup));
//更新数据库
new ScheduleManage().UpdateScheduleStatus(new ScheduleInfo() { JobName = jobName, JobGroup = jobGroup, RunStatus = (int)JobStatus.已停止 });
var status = new StatusViewModel()
{
Status = ,
Msg = "暂停任务计划成功",
}; return JsonConvert.SerializeObject(status);
}
catch (Exception ex)
{
//MyLogger.WriteError(ex, null);
var status = new StatusViewModel()
{
Status = -,
Msg = "暂停任务计划失败",
};
return JsonConvert.SerializeObject(status);
}
}
/// <summary>
/// 恢复指定的任务计划**恢复的是暂停后的任务计划,如果是程序奔溃后 或者是进程杀死后的恢复,此方法无效
/// </summary>
/// <returns></returns>
public async Task<string> RunScheduleJobAsync(string jobGroup, string jobName)
{
try
{
//获取model
var sm = new ScheduleManage().GetScheduleModel(new ScheduleInfo() { JobName = jobName, JobGroup = jobGroup });
await AddScheduleJobAsync(sm);
sm.RunStatus = (int)JobStatus.已启用;
//更新model
new ScheduleManage().UpdateScheduleStatus(sm);
scheduler = await GetSchedulerAsync();
//resumejob 恢复
await scheduler.ResumeJob(new JobKey(jobName, jobGroup)); var status = new StatusViewModel()
{
Status = ,
Msg = "开启任务计划成功",
};
return JsonConvert.SerializeObject(status);
}
catch (Exception ex)
{
var status = new StatusViewModel()
{
Status = -,
Msg = "开启任务计划失败",
};
return JsonConvert.SerializeObject(status);
}
}
}
其他几个文件的细节代码我就不再粘贴,详细代码会推到github上去,接下来写一个控制器看看效果!
第四部:项目运行截图

具体详细的东西,也没有说的十分清晰,具体的代码可以到github上去查看,
项目github地址:https://github.com/TopGuo/TB.AspNetCore.Quarzt
如果您认为这篇文章还不错或者有所收获,您可以点击右下角的【推荐】按钮精神支持,因为这种支持是我继续写作,分享的最大动力
欢迎大家关注我都我的微信 公众号,公众号涨粉丝人数,就是你们对我的喜爱程度!

Asp.Net Core 使用Quartz基于界面画接口管理做定时任务的更多相关文章
- ASP.NET Core 实战:基于 Dapper 扩展你的数据访问方法
一.前言 在非静态页面的项目开发中,必定会涉及到对于数据库的访问,最开始呢,我们使用 Ado.Net,通过编写 SQL 帮助类帮我们实现对于数据库的快速访问,后来,ORM(Object Relatio ...
- ASP.NET Core 1.0 中的依赖项管理
var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...
- asp.net core使用Swashbuckle.AspNetCore(swagger)生成接口文档
asp.net core中使用Swashbuckle.AspNetCore(swagger)生成接口文档 Swashbuckle.AspNetCore:swagger的asp.net core实现 项 ...
- 给 asp.net core 写个中间件来记录接口耗时
给 asp.net core 写个中间件来记录接口耗时 Intro 写接口的难免会遇到别人说接口比较慢,到底慢多少,一个接口服务器处理究竟花了多长时间,如果能有具体的数字来记录每个接口耗时多少,别人再 ...
- 在ASP.NET Core中创建基于Quartz.NET托管服务轻松实现作业调度
在这篇文章中,我将介绍如何使用ASP.NET Core托管服务运行Quartz.NET作业.这样的好处是我们可以在应用程序启动和停止时很方便的来控制我们的Job的运行状态.接下来我将演示如何创建一个简 ...
- Asp.net Core使用Quartz.net
1.介绍:Quartz.Net主要是用来做一些周期性的工作,或者定时工作.比如每天凌晨2点执行某个方法或者调用某个接口. Quartz项目地址:https://github.com/quartz-sc ...
- 【低码】asp.net core 实体类可生产 CRUD 后台管理界面
前言介绍 喜欢小规模团队的"单打独斗",有的时候即使在大公司,也经常做着3-5个人团队的小项目,相信很多人有类似的经历. 本文介绍如何将项目中已存在的[实体类],直接生产出 CRUD 后台管理界面. ...
- ASP.NET Core 实战:基于 Jwt Token 的权限控制全揭露
一.前言 在涉及到后端项目的开发中,如何实现对于用户权限的管控是需要我们首先考虑的,在实际开发过程中,我们可能会运用一些已经成熟的解决方案帮助我们实现这一功能,而在 Grapefruit.VuCore ...
- ASP.NET Core ResponseCaching:基于 VaryByHeader 定制缓存 Key
ASP.NET Core ResponseCaching 提供了缓存http响应内容的能力,通过它可以在本地内存中直接缓存http响应内容,这是速度最快的服务端缓存,省却了网络传输与生成响应内容的开销 ...
随机推荐
- 【Spark工作原理】stage划分原理理解
Job->Stage->Task开发完一个应用以后,把这个应用提交到Spark集群,这个应用叫Application.这个应用里面开发了很多代码,这些代码里面凡是遇到一个action操作, ...
- C#中关于as关键字的使用
我们在实际编码中有时会用到as关键字来将对象转换为指定类型,与is类型不同的是,is关键字是用于检查对象是否与给定类型兼容,如果兼容就返回true,如果不兼容就返回false.而as关键字会直接进行类 ...
- app自动化测试之实战应用(百度app简单测试)
模拟在百度app中搜索python相关内容代码如下: from appium import webdriver desired_caps = {} desired_caps['deviceName'] ...
- Spring Session - 使用Redis存储HttpSession例子
目的 使用Redis存储管理HttpSession: 添加pom.xml 该工程基于Spring Boot,同时我们将使用Spring IO Platform来维护依赖版本号: 引入的依赖有sprin ...
- WinForm版图像编辑小程序(实现图像拖动、缩放、旋转、抠图)
闲暇之余,开发一个图片编辑小程序.程序主要特点就是可方便的对多个图像编辑,实现了一些基本的操作.本文主要介绍一下程序的功能.设计思路. 执行程序 下载地址: 百度网盘.https://pan.baid ...
- Adam
Adam 方法 Adam 方法将惯性保持和环境感知这两个优点集于一身.一方面, Adam 记录梯度的一阶矩(first moment),即过往梯度与当前梯度的平均,这体现了惯性保持:另一方面,Adam ...
- ssh的两个小知识
ssh的两个小知识 1. 在ssh客户端启动远程服务器的图形界面程序. 如果你试图在ssh客户端运行远程服务器的一个图形界面程序,比如说执行firefox,此时可能会提示,can not connec ...
- ProxySQL+MGR实现读写分离和主节点故障无感知切换 - 完整操作记录
前面的文章介绍了ProxySQL用法,这里说下ProxySQL中间件针对Mysql组复制模式实现读写分离以及主节点故障时能够自动切换到新的主节点,而应用对此过程无感知的功能.Mysql组复制(MGR) ...
- (转)创建GitHub技术博客
https://blog.csdn.net/renfufei/article/details/37725057
- 基于 CGLIB 库的动态代理机制
之前的文章我们详细的介绍了 JDK 自身的 API 所提供的一种动态代理的实现,它的实现相对而言是简单的,但是却有一个非常致命性的缺陷,就是只能为接口中的方法完成代理,而委托类自己的方法或者父类中的方 ...

