今天這篇文章我将通過執行個體代碼帶着大家一步一步通過abp vNext這個asp.net core的快速開發架構來進行Quartz.net定時任務排程的管理界面的開發。大夥最好跟着一起敲一下代碼,當然源碼我會上傳到github上,有興趣的小夥伴可以在文章底部檢視源碼連結。
作者:依樂祝
原文連結:https://www.cnblogs.com/yilezhu/p/10444060.html
寫在前面
有幾天沒更新部落格了,一方面因為比較忙,另一方面是因為最近在準備組織我們霸都合肥的.NET技術社群首次非正式的線下聚會,忙着聯系人啊,這裡歡迎有興趣的小夥伴加我wx:jkingzhu進行詳細的了解,當然也歡迎同行加我微信,然後我拉你進入我們合肥.NET技術社群微信群跟大夥進行交流。
概念
開始之前還有必要跟大夥說一下abp vNext以及Quartz.net是什麼,防止有小白。如果對這兩個概念非常熟悉的話可以直接閱讀下一節。項目最終實作的效果如下圖所示:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLwADMwIjN1gDMy0SO2QTNwEzM1EzNyIDM5EDMy0CM1IzN3MTMvwlMwkTMwIzLcBTNyczNzEzLcd2bsJ2Lc12bj5ycn9Gbi52YugTMwIzZtl2Lc9CX6MHc0RHaiojIsJye.png)
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 然後如圖填寫對應的項目名稱,這裡我用的
項目類型選擇ASP.NET Core MVC應用程式,因為這個是帶有UI界面的web項目,資料庫提供程式選擇EFCore這個大家都比較熟悉,然後點選建立就可以了。Czar.AbpDemo
用abp vNext快速開發Quartz.NET定時任務管理界面 - 下載下傳後,解壓到一個檔案夾下面,然後用vs打開解決方案,看到如下圖所示的項目結構
用abp vNext快速開發Quartz.NET定時任務管理界面 - 這裡簡單介紹下,每個項目的作用,具體的就不過多介紹了,在下面的實戰代碼中慢慢體會吧
-
為領域層..Domain
-
為應用層..Application
-
為是表示層..Web
-
是EF Core內建..EntityFrameworkCore
-
- 檢視
項目下.Web
檔案中的 連接配接字元串并進行相應的修改,怎麼改不要問我:appsettings.json
{ "ConnectionStrings": { "Default": "Server=localhost;Database=CzarAbpDemo;Trusted_Connection=True;MultipleActiveResultSets=true" } }
- 右鍵單擊
項目并将其設為啟動項目.Web
用abp vNext快速開發Quartz.NET定時任務管理界面 - 打開包管理器控制台(Package Manager Console), 選擇
項目作為預設項目并運作.EntityFrameworkCore
指令:Update-Database
用abp vNext快速開發Quartz.NET定時任務管理界面 - 現在可以運作應用程式,它将會打開home頁面:
用abp vNext快速開發Quartz.NET定時任務管理界面 - 點選“Login” 輸入使用者名
, 密碼admin
1q2w3E*
, 登入應用程式.
啟動模闆包括 身份管理(identity management) 子產品. 登入後将提供身份管理菜單,你可以在其中管理角色,使用者及其權限. 這個不過多講解了,自己去動手操作一番吧
內建Quartz.NET管理功能
這部分我們将實作Quartz.NET定時任務的管理功能,為了進行Quartz.NET定時任務的管理,我們還需要定義一個表來進行Quartz.NET定時任務的資訊的承載,并完成這個表的增删改查功能,這樣我們在對這個表的資料進行操作的同時來進行Quartz.NET定時任務的操作即可實作我們的需求。話不多說,開始吧。這部分我們再分成兩個小節:JobInfo的增删改查功能的實作,Quartz.NET排程任務功能的增删改查的實作。
JobInfo的增删改查功能的實作
這個部分你将體會到我為什麼使用abp vNext架構來進行開發了,就是因為快~~~~
- 建立領域實體對象JobInfo,這個在領域層代碼如下:
用abp vNext快速開發Quartz.NET定時任務管理界面 - 将我們的JobInfo實體添加到DBContext中,這樣應該在EF層
用abp vNext快速開發Quartz.NET定時任務管理界面 - 添加新的Migration并更新到資料庫中,這個應該算EFCore的基礎了吧,兩個步驟,一個“Add-Migration” 然後“Update-Database”更新到資料庫即可
Add-Migration "Add_JobInfo_Entity" Update-Database
- 應用層建立頁面顯示實體
用來在 基礎設施層 和 應用層 傳遞資料BookDto
用abp vNext快速開發Quartz.NET定時任務管理界面 - 同樣的你還需要在應用層建立一個用來傳遞增改的Dto對象
用abp vNext快速開發Quartz.NET定時任務管理界面 - 萬事俱備,隻欠服務了,接下來我們建立一下
的服務接口以及服務接口的實作了,這裡有個約定,就是所有的服務JobInfo
結尾,就跟控制器都以AppService
結尾的概念差不多。Controller
服務實作:用abp vNext快速開發Quartz.NET定時任務管理界面 注釋還算清真,相信你應該能看懂。用abp vNext快速開發Quartz.NET定時任務管理界面 -
這裡abp vNext架構就會自動為我們實作增删改查的API Controllers接口的實作(可以通過swagger進行檢視),還會自動 為所有的API接口建立了JavaScript 代理.是以,你可以像調用 JavaScript function一樣調用任何接口.
如下圖所示
是不是,感覺什麼都還沒做,所有接口都已經實作的感覺。用abp vNext快速開發Quartz.NET定時任務管理界面 - 新增一個菜單任務排程的菜單,如下代碼所示:
用abp vNext快速開發Quartz.NET定時任務管理界面 - 對應的,我們需要在
Pages/JobSchedule
這個路徑下面建立對應的Index.cshtml頁面,以及新增,編輯的頁面。由于内容太多,這裡就不貼代碼了,隻給大家貼下圖:
Index.cshtml
CreateModal.cshtml代碼如下:用abp vNext快速開發Quartz.NET定時任務管理界面 用abp vNext快速開發Quartz.NET定時任務管理界面 - 然後我們運作起來檢視下:
用abp vNext快速開發Quartz.NET定時任務管理界面 - 點選,右上角的新增,會彈出新增界面,點選每一行的操作,會彈出删除(删除,這裡隻做了一個假功能),編輯的兩個選項。
- 到此,
的增删改查就做好了,是不是很簡單,這就是abp vNext賦予我們的高效之處。JobInfo
Quartz.NET排程任務功能的增删改的實作
在使用Quartz.NET之前,你需要通過Nuget進行下安裝,然後才能進行調用。這裡我不會給你詳細講解Quartz.NET的使用,因為這将占用大量的篇幅,并偏離本文的主旨
- 安裝Quartz.NET的Nuget包:
用abp vNext快速開發Quartz.NET定時任務管理界面 - 建立一個
的任務排程中心,代碼如下所示: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
用abp vNext快速開發Quartz.NET定時任務管理界面 - 至此Quartz.NET排程任務功能完成
內建
這裡我們按照之前的思路對
JobInfo
跟Quartz.NET任務進行內建
- 新增時,啟動任務:
用abp vNext快速開發Quartz.NET定時任務管理界面 - 編輯時,更新任務
用abp vNext快速開發Quartz.NET定時任務管理界面 - 這裡細心的網友,可能注意到任務的删除是在編輯裡面進行實作的。而清單頁面的删除功能并沒有實作真正意義的功能的删除。
功能示範
上面我們示範的任務是一個每5秒寫入目前時間的一個任務,并實作了對這個任務的新增,删除,編輯的功能,這裡大夥可以自行實作進行測試,也可以下載下傳我的代碼進行嘗試。效果圖如下所示:
功能擴充
目前隻能對既定義好任務進行排程,後期可以根據任務的名稱,如我們執行個體中的測試任務
LogTestJob
的名字找到這個任務,然後動态的進行處理。這樣就可以在界面實作對多個任務進行排程了!當然還有其他的擴充,本文隻是作為引子。
源碼位址
GitHub:https://github.com/yilezhu/AbpQuzatzDemo
總結
本文隻是簡單的利用abp vNext架構進行Quartz.NET任務排程進行UI的管理,實作的功能也比較簡單,大家完全可以在此基礎上進行擴充完善,最後感謝大夥的閱讀。
作者:依樂祝(祝雷)
出處:https://www.cnblogs.com/yilezhu
聯系:[email protected] .NET Core實戰項目交流群:637326624 微信:jkingzhu
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。如有問題或建議,請多多賜教,非常感謝。