前言:想在.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 简单定时任务框架封装