天天看點

用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快速開發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 。下面給出具體步驟:

  1. 打開https://cn.abp.io/Templates 然後如圖填寫對應的項目名稱,這裡我用的

    Czar.AbpDemo

    項目類型選擇ASP.NET Core MVC應用程式,因為這個是帶有UI界面的web項目,資料庫提供程式選擇EFCore這個大家都比較熟悉,然後點選建立就可以了。
    用abp vNext快速開發Quartz.NET定時任務管理界面
  2. 下載下傳後,解壓到一個檔案夾下面,然後用vs打開解決方案,看到如下圖所示的項目結構
    用abp vNext快速開發Quartz.NET定時任務管理界面
  3. 這裡簡單介紹下,每個項目的作用,具體的就不過多介紹了,在下面的實戰代碼中慢慢體會吧
    • .Domain

      為領域層.
    • .Application

      為應用層.
    • .Web

      為是表示層.
    • .EntityFrameworkCore

      是EF Core內建.
    解決方案還包含配置好的的單元&內建測試項目, 以便與于EF Core 和 SQLite 資料庫配合使用.
  4. 檢視

    .Web

    項目下

    appsettings.json

    檔案中的 連接配接字元串并進行相應的修改,怎麼改不要問我:
    {
      "ConnectionStrings": {
        "Default": "Server=localhost;Database=CzarAbpDemo;Trusted_Connection=True;MultipleActiveResultSets=true"
      }
    }
               
  5. 右鍵單擊

    .Web

    項目并将其設為啟動項目
    用abp vNext快速開發Quartz.NET定時任務管理界面
  6. 打開包管理器控制台(Package Manager Console), 選擇

    .EntityFrameworkCore

    項目作為預設項目并運作

    Update-Database

    指令:
    用abp vNext快速開發Quartz.NET定時任務管理界面
  7. 現在可以運作應用程式,它将會打開home頁面:
    用abp vNext快速開發Quartz.NET定時任務管理界面
  8. 點選“Login” 輸入使用者名

    admin

    , 密碼

    1q2w3E*

    , 登入應用程式.

    啟動模闆包括 身份管理(identity management) 子產品. 登入後将提供身份管理菜單,你可以在其中管理角色,使用者及其權限. 這個不過多講解了,自己去動手操作一番吧

內建Quartz.NET管理功能

這部分我們将實作Quartz.NET定時任務的管理功能,為了進行Quartz.NET定時任務的管理,我們還需要定義一個表來進行Quartz.NET定時任務的資訊的承載,并完成這個表的增删改查功能,這樣我們在對這個表的資料進行操作的同時來進行Quartz.NET定時任務的操作即可實作我們的需求。話不多說,開始吧。這部分我們再分成兩個小節:JobInfo的增删改查功能的實作,Quartz.NET排程任務功能的增删改查的實作。

JobInfo的增删改查功能的實作

這個部分你将體會到我為什麼使用abp vNext架構來進行開發了,就是因為快~~~~

  1. 建立領域實體對象JobInfo,這個在領域層代碼如下:
    用abp vNext快速開發Quartz.NET定時任務管理界面
  2. 将我們的JobInfo實體添加到DBContext中,這樣應該在EF層
    用abp vNext快速開發Quartz.NET定時任務管理界面
  3. 添加新的Migration并更新到資料庫中,這個應該算EFCore的基礎了吧,兩個步驟,一個“Add-Migration” 然後“Update-Database”更新到資料庫即可
    Add-Migration "Add_JobInfo_Entity"
    Update-Database
               
  4. 應用層建立頁面顯示實體

    BookDto

    用來在 基礎設施層 和 應用層 傳遞資料
    用abp vNext快速開發Quartz.NET定時任務管理界面
  5. 同樣的你還需要在應用層建立一個用來傳遞增改的Dto對象
    用abp vNext快速開發Quartz.NET定時任務管理界面
  6. 萬事俱備,隻欠服務了,接下來我們建立一下

    JobInfo

    的服務接口以及服務接口的實作了,這裡有個約定,就是所有的服務

    AppService

    結尾,就跟控制器都以

    Controller

    結尾的概念差不多。
    用abp vNext快速開發Quartz.NET定時任務管理界面
    服務實作:
    用abp vNext快速開發Quartz.NET定時任務管理界面
    注釋還算清真,相信你應該能看懂。
  7. 這裡abp vNext架構就會自動為我們實作增删改查的API Controllers接口的實作(可以通過swagger進行檢視),還會自動 為所有的API接口建立了JavaScript 代理.是以,你可以像調用 JavaScript function一樣調用任何接口.

    如下圖所示

    用abp vNext快速開發Quartz.NET定時任務管理界面
    是不是,感覺什麼都還沒做,所有接口都已經實作的感覺。
  8. 新增一個菜單任務排程的菜單,如下代碼所示:
    用abp vNext快速開發Quartz.NET定時任務管理界面
  9. 對應的,我們需要在

    Pages/JobSchedule

    這個路徑下面建立對應的Index.cshtml頁面,以及新增,編輯的頁面。由于内容太多,這裡就不貼代碼了,隻給大家貼下圖:

    Index.cshtml

    用abp vNext快速開發Quartz.NET定時任務管理界面
    CreateModal.cshtml代碼如下:
    用abp vNext快速開發Quartz.NET定時任務管理界面
  10. 然後我們運作起來檢視下:
    用abp vNext快速開發Quartz.NET定時任務管理界面
  11. 點選,右上角的新增,會彈出新增界面,點選每一行的操作,會彈出删除(删除,這裡隻做了一個假功能),編輯的兩個選項。
  12. 到此,

    JobInfo

    的增删改查就做好了,是不是很簡單,這就是abp vNext賦予我們的高效之處。

Quartz.NET排程任務功能的增删改的實作

在使用Quartz.NET之前,你需要通過Nuget進行下安裝,然後才能進行調用。這裡我不會給你詳細講解Quartz.NET的使用,因為這将占用大量的篇幅,并偏離本文的主旨

  1. 安裝Quartz.NET的Nuget包:
    用abp vNext快速開發Quartz.NET定時任務管理界面
  2. 建立一個

    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;//出現異常
                }
            }
        }
               
  3. LogTestJob

    的計劃任務,代碼如下所示,需要繼承

    IJob

    接口:
    用abp vNext快速開發Quartz.NET定時任務管理界面
  4. 至此Quartz.NET排程任務功能完成

內建

這裡我們按照之前的思路對

JobInfo

跟Quartz.NET任務進行內建

  1. 新增時,啟動任務:
    用abp vNext快速開發Quartz.NET定時任務管理界面
  2. 編輯時,更新任務
    用abp vNext快速開發Quartz.NET定時任務管理界面
  3. 這裡細心的網友,可能注意到任務的删除是在編輯裡面進行實作的。而清單頁面的删除功能并沒有實作真正意義的功能的删除。

功能示範

上面我們示範的任務是一個每5秒寫入目前時間的一個任務,并實作了對這個任務的新增,删除,編輯的功能,這裡大夥可以自行實作進行測試,也可以下載下傳我的代碼進行嘗試。效果圖如下所示:

用abp vNext快速開發Quartz.NET定時任務管理界面

功能擴充

目前隻能對既定義好任務進行排程,後期可以根據任務的名稱,如我們執行個體中的測試任務

LogTestJob

的名字找到這個任務,然後動态的進行處理。這樣就可以在界面實作對多個任務進行排程了!當然還有其他的擴充,本文隻是作為引子。

源碼位址

GitHub:https://github.com/yilezhu/AbpQuzatzDemo

總結

本文隻是簡單的利用abp vNext架構進行Quartz.NET任務排程進行UI的管理,實作的功能也比較簡單,大家完全可以在此基礎上進行擴充完善,最後感謝大夥的閱讀。

作者:依樂祝(祝雷)

出處:https://www.cnblogs.com/yilezhu

聯系:[email protected] .NET Core實戰項目交流群:637326624 微信:jkingzhu

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。如有問題或建議,請多多賜教,非常感謝。

用abp vNext快速開發Quartz.NET定時任務管理界面

繼續閱讀