定時器_在.net core3.0 webapi中添加自定義定時器功能

来源:https://www.cnblogs.com/lxhbky/archive/2020/01/20/12218988.html
-Advertisement-
Play Games

前言:想在.net framework環境使用自定義定時器的話,參考我的另一篇文章:https://www.cnblogs.com/lxhbky/p/10242839.html 想在.net core中使用定時器功能,需要藉助一個服務介面:IHostedService, 繼承並實現對應方法,最後再s ...


  前言:想在.net framework環境使用自定義定時器的話,參考我的另一篇文章:https://www.cnblogs.com/lxhbky/p/10242839.html

  想在.net core中使用定時器功能,需要藉助一個服務介面:IHostedService,   繼承並實現對應方法,最後再setup.cs類中添加註冊服務:services.AddHostedService<實現服務類>();   既然要寫計時器的伺服器,那麼該實現類就要包含定時器,本篇博客也是藉助System.Timers.Timer類封裝的。

 

  下麵展示具體代碼:

  1-公用基類:

  

public class ModelBase
    {
        protected IServiceProvider Services { get; set; }
        protected IWebHostEnvironment WebHostEnvironment { get; set; }
        /// <summary>
        /// 配置幫助類
        /// </summary>
        protected ConfigHelper ConfigHelper { get; set; }
        /// <summary>
        /// 等同於ASP.NET裡面的WebCache(HttpRuntime.Cache)
        /// </summary>
        protected IMemoryCache MemoryCache { get; set; }

        /// <summary>
        /// 日誌
        /// </summary>
        protected ILogger Logger { get; set; }

        /// <summary>
        /// 授權幫助
        /// </summary>
        protected OAuthHelper OAuthHelper { get; set; }

        /// <summary>
        /// HttpClient幫助工廠
        /// </summary>
        protected IHttpClientFactory HttpClientFactory { get; set; }


        public ModelBase(params object[] @params)
        {
            foreach (var item in @params)
            {
                if (item is IServiceProvider)
                {
                    this.Services = (IServiceProvider)item;
                }
                else if (item is IWebHostEnvironment)
                {
                    this.WebHostEnvironment = (IWebHostEnvironment)item;
                }
                else if (item is ConfigHelper)
                {
                    this.ConfigHelper = (ConfigHelper)item;
                }
                else if (item is IMemoryCache)
                {
                    this.MemoryCache = (IMemoryCache)item;
                }
                else if (item is ILogger)
                {
                    this.Logger = (ILogger)item;
                }
                else if (item is OAuthHelper)
                {
                    this.OAuthHelper = (OAuthHelper)item;
                }
                else if (item is IHttpClientFactory)
                {
                    this.HttpClientFactory = (IHttpClientFactory)item;
                }
                
            }

        }
    }

  

  2-計時器封裝類:

  相對於.net framework文章計時器部分的類做了對應優化,更加簡化了:

using Microsoft.Extensions.Logging;
using PaymentAccountAPI.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Timers;

namespace PaymentAccountAPI.Helper
{
    /// <summary>
    /// 定時周期幫助類
    /// </summary>
    public class TimeCycleHelp : ModelBase
    {
        public TimeCycleHelp(ILogger<TimeCycleHelp> logger) : base(logger)
        {
            this.Timer = new System.Timers.Timer();
        }

        /// <summary>
        /// 服務專屬計時器
        /// </summary>
        private System.Timers.Timer Timer;

        /// <summary>
        /// 預設計時器時間間隔1秒(提高計時器開始時間準確度)
        /// </summary>
        private double DefaultTimerInterval = 1 * 1000;

        /// <summary>
        /// 設置多個迴圈周期
        /// </summary>
        private List<TimeCycle> TimeCycleList { get; set; }


        /// <summary>
        /// 更新一個計時器的計時周期
        /// </summary>
        /// <param name="newTimerInterval">新的計時周期</param>
        /// <param name="isFirstStart">是否是首次更新計時器周期</param>
        private void UpdateTimeInterval(double newTimerInterval, bool isFirstStart = false)
        {
            if (this.Timer != null && newTimerInterval > 0)
            {
                this.Timer.Stop();
                if (this.Timer.Interval != newTimerInterval)
                {
                    this.Timer.Interval = newTimerInterval;
                }
                if (isFirstStart)
                {
                    this.Timer.Elapsed += new System.Timers.ElapsedEventHandler(this.ServiceAction);
                }
                this.Timer.AutoReset = true;
                this.Timer.Start();
            }
        }

        /// <summary>
        /// 內部輔助方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ServiceAction(object sender, ElapsedEventArgs e)
        {
            List<TimeCycle> currentTimeCycleList = new List<TimeCycle>(0);

            DateTime now = DateTime.Now;
            DateTime cycleBeginTime;
            DateTime cycleEndTime;
            foreach (TimeCycle timeCycle in this.TimeCycleList)
            {
                cycleBeginTime = Convert.ToDateTime(timeCycle.BeginTime);
                cycleBeginTime = now.Date.AddHours(cycleBeginTime.Hour).AddMinutes(cycleBeginTime.Minute).AddSeconds(cycleBeginTime.Second);
                cycleEndTime = Convert.ToDateTime(timeCycle.EndTime);
                cycleEndTime = now.Date.AddHours(cycleEndTime.Hour).AddMinutes(cycleEndTime.Minute).AddSeconds(cycleEndTime.Second);
                if (cycleEndTime < cycleBeginTime)
                {
                    cycleEndTime = cycleEndTime.AddDays(1);
                }

                if (now >= cycleBeginTime && now <= cycleEndTime)
                {
                    //有最大執行次數限制或者沒有限制
                    if (timeCycle.ActionExecutionTimes < timeCycle.MaxActionTimes || timeCycle.MaxActionTimes == 0)
                    {
                        TimeSpan timeSpan = now - cycleBeginTime;
                        bool isCanAction = (int)timeSpan.TotalSeconds % timeCycle.ActionSeconds == 0 ? true : false;
                        if (isCanAction)
                        {
                            timeCycle.ActionExecutionTimes++;
                            currentTimeCycleList.Add(timeCycle);
                        }
                    }
                }
                else
                {
                    //不在計時周期內,已執行次數清零
                    timeCycle.ActionExecutionTimes = 0;
                }
            }
            //找到當前迴圈周期後,執行周期內動作
            if (currentTimeCycleList.Count > 0)
            {
                currentTimeCycleList.ForEach(item =>
                {
                    //使用多線程執行任務,讓代碼快速執行
                    Task.Run(() => item.Action());
                });
            }
        }

        /// <summary>
        /// 開啟計時器
        /// </summary>
        /// <param name="timeCycleArray"></param>
        public void Start(params TimeCycle[] timeCycleArray)
        {
            if (timeCycleArray != null && timeCycleArray.Length > 0)
            {
                if (this.TimeCycleList == null)
                {
                    this.TimeCycleList = new List<TimeCycle>(100);
                }
                this.TimeCycleList = timeCycleArray.ToList();

                //設置首次計時器周期(首次動作執行,是在計時器啟動後在設置的時間間隔後做出的動作)
                this.UpdateTimeInterval(this.DefaultTimerInterval, true);
            }
        }

        /// <summary>
        /// 結束計時器
        /// </summary>
        public void Stop()
        {
            this.Timer.Stop();
        }

    }

    /// <summary>
    /// 計時周期類
    /// </summary>
    public class TimeCycle
    {
        /// <summary>
        /// 唯一標識
        /// </summary>
        public int ID { get; set; }
        /// <summary>
        /// 開始時間(誤差1秒=取決於計時器預設時間間隔)
        /// </summary>
        public string BeginTime { get; set; }
        /// <summary>
        /// 結束時間
        /// </summary>
        public string EndTime { get; set; }
        /// <summary>
        /// 最大執行次數
        /// </summary>
        public int MaxActionTimes { get; set; }
        /// <summary>
        /// 計時周期內執行的動作(動作會在到達開始時間後的)
        /// </summary>
        public Action Action { get; set; }
        /// <summary>
        /// 動作執行時間間隔(秒)
        /// </summary>
        public int ActionSeconds { get; set; }
        /// <summary>
        /// 方法執行次數
        /// </summary>
        internal int ActionExecutionTimes { get; set; }

        public TimeCycle(int id, Action action, int actionSeconds) : this(id, "00:00:00", action, actionSeconds)
        {
        }

        public TimeCycle(int id, string beginTime, Action action, int actionSeconds) : this(id, beginTime, action, actionSeconds, 0)
        {
        }

        public TimeCycle(int id, string beginTime, Action action, int actionSeconds, int maxActionTimes) : this(id, beginTime, "23:59:59", action, actionSeconds, maxActionTimes)
        {
        }

        /// <summary>
        /// 基本構造器
        /// </summary>
        /// <param name="id">唯一標識</param>
        /// <param name="beginTime">開始時間</param>
        /// <param name="endTime">結束時間</param>
        /// <param name="action">要執行的任務</param>
        /// <param name="actionSeconds">任務執行時間間隔</param>
        /// <param name="maxActionTimes">最大執行次數</param>
        public TimeCycle(int id, string beginTime, string endTime, Action action, int actionSeconds, int maxActionTimes)
        {
            this.ID = id;
            this.BeginTime = beginTime;
            this.EndTime = endTime;
            this.Action = action;
            this.ActionSeconds = actionSeconds;
            this.MaxActionTimes = maxActionTimes;
        }
    }
}

 

  3-webAPI服務封裝類:

  

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using PaymentAccountAPI.Common;
using PaymentAccountAPI.Helper;
using PaymentAccountAPI.PaymentAccountHelper;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace PaymentAccountAPI.Hangfire
{
    public class SyncToCMSService : ModelBase, IHostedService
    {private TimeCycleHelp _TimeCycleHelp { get; set; }

        public SyncToCMSService(ConfigHelper configHelper,
                                TimeCycleHelp timeCycleHelp, ILogger<SyncToCMSService> logger) : base(logger, configHelper)
        {this._TimeCycleHelp = timeCycleHelp;
        }

        public void SyncData()
        {
           //...需要執行的任務代碼

            this.Logger.LogInformation($"定時任務:完成{currentDate.ToShortDateString()}的交易記錄同步!");
        }



        public Task StartAsync(CancellationToken cancellationToken)
        {
            this.Logger.LogInformation($"定時任務:同步服務已啟動...");

            //正式代碼
            string syncBeginTime = this.ConfigHelper.GetAppSettingValue("SyncCMSBeginTime");
            string syncEndTime = this.ConfigHelper.GetAppSettingValue("SyncCMSEndTime");
            this._TimeCycleHelp.Start(new TimeCycle(999, syncBeginTime, syncEndTime, this.SyncData, 3600, 2));

            //測試代碼
            //this._TimeCycleHelp.Start(new TimeCycle(999, "12:00:00", () =>
            //{
            //    this.Logger.LogInformation("test123");
            //}, 10, 3));

            return Task.CompletedTask;
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            this.Logger.LogInformation($"同步服務已停止...");
            this._TimeCycleHelp.Stop();

            return Task.CompletedTask;
        }

    }
}

 

  4-在startup.cs添加註冊服務:

  

            #region 添加定時任務

            services.AddSingleton<TimeCycleHelp>();

            services.AddHostedService<SyncToCMSService>();

            #endregion

 

 

  最後感謝一篇道友的文章:.Net Core 簡單定時任務框架封裝


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

-Advertisement-
Play Games
更多相關文章
  • 引言 昨日接了一個阿裡外包的電話面試,問了一些技術問題感覺到自己是真的菜,接觸Java開發已經也有一段時間,技術方面說來慚愧,一直以來只是局限於框架工具的用法,也沒有進行瞭解其實現的原理,更重要的是一直沒有歸納和總結,這次把這些問題記錄下來,相關的知識點也找了一些資料學習下。 問題 1. Count ...
  • 錯誤信息 錯誤原因 so文件損壞 或者ida換成32 解決辦法 重新獲得so文件,或者調整ida的位數 ...
  • 在JAVA中集合是一種比較基礎重要的數據結構,對集合的常用操作,不同集合直接的比較是非常重要的,這裡ConcurrentHashMap是一個線程安全並且效率非常高的集合,主要講解這裡如何去使用這個集合,和集合的效率比較 ...
  • 首先需要pip3 install wakeonlan 然後在電腦需要你的網卡支持網路喚醒電腦。 然後在主板BIOS開啟支持喚醒。 在系統網卡屬性里選上“允許電腦關閉此設備以節約電源”,“允許此設備喚醒電腦” 然後以下就是python代碼,非常簡單。from wakeonlan import s ...
  • 本篇博客園是被任務所逼,而已有的使用nopi技術的文檔技術經驗又不支持我需要的應對各種複雜需求的苛刻要求,只能自己造輪子封裝了,由於需要應對很多總類型的數據採集需求,因此有了本篇博客的代碼封裝,下麵一點點介紹吧: 收集excel你有沒有遇到過一下痛點: 1-需要收集指定行標題位置的數據,我的標題行不 ...
  • linqtocsv文件有不太好的地方就是:無法設置標題的行數,預設首行就是標題,這不是很尷尬嗎? 並不是所有的csv文件嚴格寫的首行是標題,下麵全是數據,我接受的任務就是讀取很多.csv報表數據,裡面就有很多前幾行是說明性內容,下麵才是標題和數據。為了更好的解決這個問題,自己寫吧... 本博客沒有照 ...
  • 本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/7723225.html,記錄一下學習過程以備後續查用。 一、引言 今天我們要講結構型設計模式的第三個模式--裝飾模式。當第一次看到這個名稱時想到的是另外一個詞語“裝修”,個人觀點談談對“裝修”的理解吧,請大家 ...
  • 在上一篇文章:《閃電光速拳? .NetCore 中的Span》中我們提到了在.net core 2.x 所新增的一個類型:Span。但是您會發現它無法用在我們項目的某些地方,它獨特的 ref結構 使它沒有辦法跨線程使用、更沒有辦法使用Lambda表達式。所以,這個時候如果我們又想跨線程操作數據又想獲... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...