上一章介绍了log4net的简单配置,这一章介绍一下quartz的简单使用,下一章介绍一下我得权限使用,然后就结束
本章主要介绍:
- quartz在asp.net core中的使用
这个项目虽小,但是及其容易扩展,后面的业务直接能丢进来,使其更加丰富
废话不说开始介绍
一.基础类配置
在domain里定义IJobCenter接口
代码如下:
public interface IJobCenter { ////// 添加定时任务 /// /// /// Task AddScheduleJobAsync(TaskScheduleModel m); /// /// 暂停定时任务 /// /// /// /// Task StopScheduleJobAsync(string jobGroup, string jobName); /// /// 恢复定时任务 /// /// /// /// Task RunScheduleJobAsync(TaskScheduleModel m); }
infrastructure里实现IJobCenter
记得引入quartz的nuget
代码如下:
////// 任务调度中心 /// public class JobCenter:IJobCenter { public static IScheduler scheduler = null; public static async Task GetSchedulerAsync() { if (scheduler != null) { return scheduler; } else { ISchedulerFactory schedf = new StdSchedulerFactory(); IScheduler sched = await schedf.GetScheduler(); return sched; } } /// /// 添加任务计划//或者进程终止后的开启 /// /// public async Task AddScheduleJobAsync(TaskScheduleModel m) { Result result = new Result(); try { if (m != null) { DateTimeOffset starRunTime = DateBuilder.NextGivenSecondDate(m.StarRunTime, 1); DateTimeOffset endRunTime = DateBuilder.NextGivenSecondDate(m.EndRunTime, 1); scheduler = await GetSchedulerAsync(); IJobDetail job = JobBuilder.Create () .WithIdentity(m.JobName, m.JobGroup) .Build(); ICronTrigger trigger = (ICronTrigger)TriggerBuilder.Create() .StartAt(starRunTime) .EndAt(endRunTime) .WithIdentity(m.JobName, m.JobGroup) .WithCronSchedule(m.CronExpress) .Build(); await scheduler.ScheduleJob(job, trigger); await scheduler.Start(); result.Data = m; return result; } return result.SetError("传入实体为空"); } catch (Exception ex) { Log4Net.Error($"[JobCenter_AddScheduleJobAsync]_{ex}"); return result.SetError(ex.Message); } } /// /// 暂停指定任务计划 /// /// public async Task StopScheduleJobAsync(string jobGroup, string jobName) { Result result = new Result(); try { scheduler = await GetSchedulerAsync(); //使任务暂停 await scheduler.PauseJob(new JobKey(jobName, jobGroup)); var status = new StatusViewModel() { Status = 0, Msg = "暂停任务计划成功", }; result.Data = status.GetJson(); return result; } catch (Exception ex) { Log4Net.Error($"[JobCenter_StopScheduleJobAsync]_{ex}"); var status = new StatusViewModel() { Status = -1, Msg = "暂停任务计划失败", }; result.Data = status.GetJson(); return result; } } /// /// 恢复指定的任务计划**恢复的是暂停后的任务计划,如果是程序奔溃后 或者是进程杀死后的恢复,此方法无效 /// /// public async Task RunScheduleJobAsync(TaskScheduleModel sm) { Result result = new Result(); try { #region 开任务 //scheduler = await GetSchedulerAsync(); //DateTimeOffset starRunTime = DateBuilder.NextGivenSecondDate(sm.StarRunTime, 1); //DateTimeOffset endRunTime = DateBuilder.NextGivenSecondDate(sm.EndRunTime, 1); //IJobDetail job = JobBuilder.Create () // .WithIdentity(sm.JobName, sm.JobGroup) // .Build(); //ICronTrigger trigger = (ICronTrigger)TriggerBuilder.Create() // .StartAt(starRunTime) // .EndAt(endRunTime) // .WithIdentity(sm.JobName, sm.JobGroup) // .WithCronSchedule(sm.CronExpress) // .Build(); //await scheduler.ScheduleJob(job, trigger); //await scheduler.Start(); #endregion scheduler = await GetSchedulerAsync(); //resumejob 恢复 await scheduler.ResumeJob(new JobKey(sm.JobName, sm.JobGroup)); var status = new StatusViewModel() { Status = 0, Msg = "恢复任务计划成功", }; result.Data = status.GetJson(); return result; } catch (Exception ex) { Log4Net.Error($"[JobCenter_RunScheduleJobAsync]_{ex}"); var status = new StatusViewModel() { Status = -1, Msg = "恢复任务计划失败", }; result.Data = status.GetJson(); return result; } } }
写一个JobServiceExtensions拓展,其中里面有一个AddJobSerivce,用于在startup里添加启动服务
这个拓展的主要作用是:程序启动,自动查询我的任务调度管理表,查询里面的状态是开启中的任务,并将其添加到定时任务中
表结构大致如下:
这里我们主要注意任务组和任务名,这两个何在一起,能顶一个唯一的任务,后面我们会在httpjob里根据不同的的任务组和任务名
区分他们要执行的不同的逻辑
代码很简单:如下
public class HttpJob : IJob { ////// 通过group和name判断是要执行哪个任务 具体(任务执行逻辑)业务逻辑写后面 /// /// /// public async Task Execute(IJobExecutionContext context) { await Task.Run(() => { var name = context.JobDetail.Key.Name; var group = context.JobDetail.Key.Group; if (group=="xx1"&&name=="xx2") { //do something } if (group == "xx2" && name == "xx3") { //do something also } Log4Net.Info($"执行任务_Name:{name}_Grop:{group}"); }); } }
在domain里新增ITaskService接口,如下
代码如下:
public interface ITaskService { //获取任务列表 Result GetTaskList(); //添加任务 TaskAddTaskAsync(TaskScheduleModel model); //修改任务 Task ModifyTaskAsync(TaskScheduleModel model); //删除任务 Task DelTaskAsync(TaskScheduleModel model); //暂停任务 Result PauseTask(); //开启任务 Result StartTask(); }
在application 里实现这个接口
代码如下:
public class TaskService : BaseService, ITaskService { private IJobCenter jobCenter = ServiceCollectionExtension.Get(); private MvcIdentity identity = (ServiceCollectionExtension.HttpContext.User.Identity as MvcIdentity); public async Task AddTaskAsync(TaskScheduleModel model) { Result result = new Result(); if (model == null) { return result.SetError("Model 不能为空!"); } if (string.IsNullOrEmpty(model.JobName)) { return result.SetError("JobName 不能为空!"); } if (string.IsNullOrEmpty(model.JobGroup)) { return result.SetError("JobGroup 不能为空!"); } if (model.StarRunTime == null) { model.StarRunTime = DateTime.Now; } if (model.EndRunTime == null) { model.EndRunTime = DateTime.MaxValue.AddDays(-1); } var info = await jobCenter.AddScheduleJobAsync(model); if (info.Status != 200) { return result.SetError(info.Message); } base.Add(new TaskSchedule { Id = Guid.NewGuid().ToString("N"), CreateAuthr = identity.Name, CronExpress = model.CronExpress, EndRunTime = model.EndRunTime, StarRunTime = model.StarRunTime, JobGroup = model.JobGroup, JobName = model.JobName, RunStatus = model.RunStatus }, true); return result; } public async Task DelTaskAsync(TaskScheduleModel model) { Result result = new Result(); if (model == null) { return result.SetError("Model 不能为空!"); } if (string.IsNullOrEmpty(model.JobName)) { return result.SetError("JobName 不能为空!"); } if (string.IsNullOrEmpty(model.JobGroup)) { return result.SetError("JobGroup 不能为空!"); } //search var taskInfo = base.Single (t => t.Id.Equals(model.Id)); var info = await jobCenter.StopScheduleJobAsync(model.JobGroup, model.JobName); if (!info.Status.Equals(200)) { return result.SetError(info.Message); } //del base.Delete(taskInfo, true); return result; } public Result GetTaskList() { Result result = new Result(); var query = base.Where (t => !t.RunStatus.Equals(TaskJobStatus.JobHasDel)).Select(t => new { t.Id, t.JobGroup, t.JobName, t.RunStatus, t.StarRunTime, t.UpdateTime, t.CronExpress, t.EndRunTime, t.CreateTime }).ToList(); List _list = new List (); query.ForEach(t => { _list.Add(new TaskScheduleModel() { Id = t.Id, JobGroup = t.JobGroup, JobName = t.JobName, _RunStatus = ((TaskJobStatus)t.RunStatus).GetString(), StarRunTime = t.StarRunTime, UpdateTime = t.UpdateTime, CronExpress = t.CronExpress, EndRunTime = t.EndRunTime, CreateTime = t.CreateTime }); }); result.Data = _list; return result; } public async Task ModifyTaskAsync(TaskScheduleModel model) { Result result = new Result(); if (model == null) { return result.SetError("Model 不能为空!"); } if (string.IsNullOrEmpty(model.JobName)) { return result.SetError("JobName 不能为空!"); } if (string.IsNullOrEmpty(model.JobGroup)) { return result.SetError("JobGroup 不能为空!"); } if (model.StarRunTime == null) { model.StarRunTime = DateTime.Now; } if (model.EndRunTime == null) { model.EndRunTime = DateTime.MaxValue.AddDays(-1); } //modify var taskInfo = base.Single (t => t.Id.Equals(model.Id)); if (taskInfo == null) { return result.SetError("无此任务!"); } //cron if (!taskInfo.CronExpress.Equals(model.CronExpress)) { taskInfo.CronExpress = model.CronExpress; var stopInfo = await jobCenter.StopScheduleJobAsync(model.JobGroup, model.JobName); if (!stopInfo.Status.Equals(200)) { return result.SetError(stopInfo.Message); } var info = await jobCenter.AddScheduleJobAsync(model); if (!stopInfo.Status.Equals(200)) { return result.SetError(info.Message); } } //状态 if (!taskInfo.RunStatus.Equals(model.RunStatus)) { taskInfo.RunStatus = model.RunStatus; if (model.RunStatus != (int)TaskJobStatus.PauseJob) { var stopInfo = await jobCenter.StopScheduleJobAsync(model.JobGroup, model.JobName); if (!stopInfo.Status.Equals(200)) { return result.SetError(stopInfo.Message); } var info = await jobCenter.AddScheduleJobAsync(model); if (!stopInfo.Status.Equals(200)) { return result.SetError(info.Message); } } else { var stopInfo = await jobCenter.StopScheduleJobAsync(model.JobGroup, model.JobName); if (!stopInfo.Status.Equals(200)) { return result.SetError(stopInfo.Message); } } } // taskInfo.CreateAuthr = identity.Name; taskInfo.UpdateTime = DateTime.Now; taskInfo.EndRunTime = model.EndRunTime; taskInfo.StarRunTime = model.StarRunTime; taskInfo.JobGroup = model.JobGroup; taskInfo.JobName = model.JobName; base.Update(taskInfo, true); return result; } public Result PauseTask() { throw new NotImplementedException(); } public Result StartTask() { throw new NotImplementedException(); } }
接着我们构建web页面
在website里创建taskinfo控制器
代码很简单只是做了一个跳转
创建视图
代码如下:
@{ ViewData["title"] = "定时任务管理"; }class="row search">@*弹出框*@class="form-inline"> "text" class="form-control" placeholder="任务名称" ng-model="search.username" />class="modal fade in" id="addmodel" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="mymodallabel">class="modal-dialog modal-lg" role="document" style="height:100%">class="modal-content">class="modal-header">计划任务管理
class="modal-body" ng-form="mymodel">class="row">class="form-group col-sm-6">class="col-sm-8"> "text" class="form-control" ng-model="task.jobGroup" required placeholder="任务组" />class="form-group col-sm-6">class="col-sm-8"> "text" class="form-control" ng-model="task.jobName" required placeholder="任务名称" />class="form-group col-sm-6">class="col-sm-8"> "text" class="form-control" ng-model="task.cronExpress" required placeholder="CronExpress" />class="form-group col-sm-6">class="col-sm-8"> <select class="form-control" required ng-model="task.runStatus"> @**@ select>class="form-group col-sm-6">class="col-sm-8"> "text" class="form-control mydatetimepicker" ng-model="task.starRunTime" ng-max-date="task.starRunTime||defaultDate" placeholder="开始日期" />class="form-group col-sm-6">class="col-sm-8"> "text" class="form-control mydatetimepicker" ng-model="task.endRunTime" ng-min-date="task.starRunTime" ng-max-date="defaultDate" placeholder="结束日期" />class="modal-footer">
任务组 | 任务 | CronExpress | 开始时间 | 结束时间 | 运行状态 | 创建时间 | 修改时间 | 操作 |
---|---|---|---|---|---|---|---|---|
{{m.jobGroup}} | {{m.jobName}} | {{m.cronExpress}} | {{m.starRunTime}} | {{m.endRunTime}} | {{m._RunStatus}} | {{m.createTime}} | {{m.updateTime}} |
- "search.recordcount" items-per-page="search.pagesize" ng-change="pagechanged()" ng-model="search.pageindex" max-size="7"
class="pagination-sm" boundary-links="true" num-pages="search.numpages" boundary-link-numbers="true" first-text="首页" last-text="末页" previous-text="上一页" next-text="下一页">
之后效果就出来了
这个table会调用一个webapi接口获取数据
这个webapi里我们直接调用我们改才ITaskService里分装的方法
这里代码如下:
#region 计划任务模块 [HttpPost] public Result GetTaskList() { return _taskService.GetTaskList(); } [HttpPost] public async TaskAddTaskAsync([FromBody]TaskScheduleModel model) { if (model != null && !string.IsNullOrEmpty(model.Id)&&!model.Id.Equals("-1")) { return await _taskService.ModifyTaskAsync(model); } return await _taskService.AddTaskAsync(model); } public async Task DelTaskAsync([FromBody]TaskScheduleModel model) { return await _taskService.DelTaskAsync(model); } #endregion
二.运行测试
换得添加服务哦
算了,这个运行测试截图不好说明,明天录一个视频说明一下,今天就到这里
下一章主要说一下权限这块的东西,本来想着今天就写完的,但是有点困了,
此文章献给我做一年半asp.net core开发的青春岁月,晚安!