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

来源:https://www.cnblogs.com/yilezhu/archive/2019/02/27/10444060.html
-Advertisement-
Play Games

今天這篇文章我將通過實例代碼帶著大家一步一步通過abp vNext這個asp.net core的快速開發框架來進行Quartz.net定時任務調度的管理界面的開發。大伙最好跟著一起敲一下代碼,當然源碼我會上傳到github上,有興趣的小伙伴可以在文章底部查看源碼鏈接。 作者:依樂祝 原文鏈接:htt ...


今天這篇文章我將通過實例代碼帶著大家一步一步通過abp vNext這個asp.net core的快速開發框架來進行Quartz.net定時任務調度的管理界面的開發。大伙最好跟著一起敲一下代碼,當然源碼我會上傳到github上,有興趣的小伙伴可以在文章底部查看源碼鏈接。

作者:依樂祝
原文鏈接:https://www.cnblogs.com/yilezhu/p/10444060.html

寫在前面

有幾天沒更新博客了,一方面因為比較忙,另一方面是因為最近在準備組織我們霸都合肥的.NET技術社區首次非正式的線下聚會,忙著聯繫人啊,這裡歡迎有興趣的小伙伴加我wx:jkingzhu進行詳細的瞭解,當然也歡迎同行加我微信,然後我拉你進入我們合肥.NET技術社區微信群跟大伙進行交流。

概念

開始之前還有必要跟大伙說一下abp vNext以及Quartz.net是什麼,防止有小白。如果對這兩個概念非常熟悉的話可以直接閱讀下一節。項目最終實現的效果如下圖所示:

1551252591337

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這個大家都比較熟悉,然後點擊創建就可以了。

    1551248124416

  2. 下載後,解壓到一個文件夾下麵,然後用vs打開解決方案,看到如下圖所示的項目結構

    1551248279486

  3. 這裡簡單介紹下,每個項目的作用,具體的就不過多介紹了,在下麵的實戰代碼中慢慢體會吧

    • .Domain 為領域層.
    • .Application 為應用層.
    • .Web 為是表示層.
    • .EntityFrameworkCore 是EF Core集成.

    解決方案還包含配置好的的單元&集成測試項目, 以便與於EF CoreSQLite 資料庫配合使用.

  4. 查看.Web項目下appsettings.json文件中的 連接字元串併進行相應的修改,怎麼改不要問我:

    {
      "ConnectionStrings": {
        "Default": "Server=localhost;Database=CzarAbpDemo;Trusted_Connection=True;MultipleActiveResultSets=true"
      }
    }
  5. 右鍵單擊.Web項目並將其設為啟動項目

    1551248539374

  6. 打開包管理器控制台(Package Manager Console), 選擇.EntityFrameworkCore項目作為預設項目並運行Update-Database命令:

    1551248591831

  7. 現在可以運行應用程式,它將會打開home頁面:

    1551248689114

  8. 點擊“Login” 輸入用戶名admin, 密碼1q2w3E*, 登錄應用程式.

    啟動模板包括 身份管理(identity management) 模塊. 登錄後將提供身份管理菜單,你可以在其中管理角色,用戶及其許可權. 這個不過多講解了,自己去動手操作一番吧

集成Quartz.NET管理功能

這部分我們將實現Quartz.NET定時任務的管理功能,為了進行Quartz.NET定時任務的管理,我們還需要定義一個表來進行Quartz.NET定時任務的信息的承載,並完成這個表的增刪改查功能,這樣我們在對這個表的數據進行操作的同時來進行Quartz.NET定時任務的操作即可實現我們的需求。話不多說,開始吧。這部分我們再分成兩個小節:JobInfo的增刪改查功能的實現,Quartz.NET調度任務功能的增刪改查的實現。

JobInfo的增刪改查功能的實現

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

  1. 創建領域實體對象JobInfo,這個在領域層代碼如下:

    1551249480050

  2. 將我們的JobInfo實體添加到DBContext中,這樣應該在EF層

    1551249406105

  3. 添加新的Migration並更新到資料庫中,這個應該算EFCore的基礎了吧,兩個步驟,一個“Add-Migration” 然後“Update-Database”更新到資料庫即可

    Add-Migration "Add_JobInfo_Entity"
    Update-Database
  4. 應用層創建頁面顯示實體BookDto 用來在 基礎設施層 和 應用層 傳遞數據

    1551249983515

  5. 同樣的你還需要在應用層創建一個用來傳遞增改的Dto對象
    1551250041669

  6. 萬事俱備,只欠服務了,接下來我們創建一下JobInfo的服務介面以及服務介面的實現了,這裡有個約定,就是所有的服務AppService結尾,就跟控制器都以Controller結尾的概念差不多。

    1551250166378

    服務實現:

    1551250189323

    註釋還算清真,相信你應該能看懂。

  7. 這裡abp vNext框架就會自動為我們實現增刪改查的API Controllers介面的實現(可以通過swagger進行查看),還會自動 為所有的API介面創建了JavaScript 代理.因此,你可以像調用 JavaScript function一樣調用任何介面.

    如下圖所示

    1551250400532
    是不是,感覺什麼都還沒做,所有介面都已經實現的感覺。

  8. 新增一個菜單任務調度的菜單,如下代碼所示:

    1551250546971

  9. 對應的,我們需要在Pages/JobSchedule 這個路徑下麵創建對應的Index.cshtml頁面,以及新增,編輯的頁面。由於內容太多,這裡就不貼代碼了,只給大家貼下圖:

    Index.cshtml

    1551250659492

    CreateModal.cshtml代碼如下:

    1551250688733

  10. 然後我們運行起來查看下:

    1551250773502

  11. 點擊,右上角的新增,會彈出新增界面,點擊每一行的操作,會彈出刪除(刪除,這裡只做了一個假功能),編輯的兩個選項。

  12. 到此,JobInfo的增刪改查就做好了,是不是很簡單,這就是abp vNext賦予我們的高效之處。

Quartz.NET調度任務功能的增刪改的實現

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

  1. 安裝Quartz.NET的Nuget包:

    1551251014507

  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介面:

    1551251169229

  4. 至此Quartz.NET調度任務功能完成

集成

這裡我們按照之前的思路對JobInfo跟Quartz.NET任務進行集成

  1. 新增時,啟動任務:

    1551251315532

  2. 編輯時,更新任務

    1551251351318

  3. 這裡細心的網友,可能註意到任務的刪除是在編輯裡面進行實現的。而列表頁面的刪除功能並沒有實現真正意義的功能的刪除。

功能演示

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

1551251560062

功能擴展

目前只能對既定義好任務進行調度,後期可以根據任務的名稱,如我們實例中的測試任務LogTestJob 的名字找到這個任務,然後動態的進行處理。這樣就可以在界面實現對多個任務進行調度了!當然還有其他的擴展,本文只是作為引子。

源碼地址

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

總結

本文只是簡單的利用abp vNext框架進行Quartz.NET任務調度進行UI的管理,實現的功能也比較簡單,大家完全可以在此基礎上進行擴展完善,最後感謝大伙的閱讀。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在應用程式的開發中,如果資料庫中的數據量過於的龐大,則需要針對查詢數據做分頁處理,取出對應分頁中的數據,在Sqlserver分頁的語句寫法中,有兩種比較常用,一種是數據表中含有自增量Id的情況,可以根據Id的大小順序進行分頁,另一種是資料庫中不存在Int類型的Id的情況,此時就需要通過Row_Num ...
  • //實現層 分割線 public List<UserModel> ShowListPage(int pageindex, int pagesize) { string sql = string.Format("select top({0}) *from (select ROW_NUMBER() ov ...
  • 管理各種管理器 ///為什麼需要單例 ///單例模式核心在於對於某個單例類,在系統中同時只存在唯一一個實例,並且該實例容易被外界所訪問; ///避免創建過多的對象,意味著在記憶體中,只存在一個實例,減少了記憶體開銷; using System.Collections; using System.Coll ...
  • 在打開from設計界面時,報錯。 解決方法:將項目中Properties文件中licenses.licx刪除,重新建立一個空的licenses.licx文件放到項目中。 重新打開界面,解決 ...
  • 效果展示(尚未完善) using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Threading; using System.Net; using System.Net.S ...
  • 項目中我們常常會碰到一些數據,需要高頻率用到但是又不會頻繁變動的這類,我們就可以使用緩存把這些數據緩存起來(比如說本項目的導航數據,帖子頻道數據). 我們項目中常用到有Asp.Net Core 本身提供的緩存組件MemoryCache以及第三方緩存組件Redis(當然這個不僅僅只用來做緩存工具用). ...
  • 綜合網上資源完成的自己的第一篇博客 網上類似的貼子挺多的,由於情況不太一樣。網上相關帖子都是在 MainWindow 嵌入。我需要在原有客戶端上開發新的插件即用戶控制項庫實現嵌入外部exe。 主要問題:獲取不到視窗句柄。 1、利用系統API實現嵌入。 2、當時在獲取頁面(用戶控制項庫)的句柄問題上碰壁, ...
  • 下載了codesmith 8,連接Mysql卻提示“找不到請求的 .Net Framework Data Provider"。 1,下載MySql.Data.dll:https://dev.mysql.com/downloads/windows/visualstudio/ 下載zip格式的即可,解壓 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...