定时器_在.net core3.0 webapi中添加自定义定时器功能
前言:想在.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 { ; } /// <summary> /// 配置帮助类 </summary> protected ConfigHelper ConfigHelper { 等同于ASP.NET里面的WebCache(HttpRuntime.Cache) protected IMemoryCache MemoryCache { ; } 日志 protected ILogger Logger { 授权帮助 protected OAuthHelper OAuthHelper { HttpClient帮助工厂 protected IHttpClientFactory HttpClientFactory { ; } public ModelBase(params object[] @params) { foreach (var item in @params) { if (item is IServiceProvider) { this.Services = (IServiceProvider)item; } else IWebHostEnvironment) { this.WebHostEnvironment = (IWebHostEnvironment)item; } ConfigHelper) { this.ConfigHelper = (ConfigHelper)item; } IMemoryCache) { this.MemoryCache = (IMemoryCache)item; } ILogger) { this.Logger = (ILogger)item; } OAuthHelper) { this.OAuthHelper = (OAuthHelper)item; } IHttpClientFactory) { this.HttpClientFactory = (IHttpClientFactory)item; } } } }
2-计时器封装类: 相对于.net framework文章计时器部分的类做了对应优化,更加简化了: using Microsoft.Extensions.Logging; PaymentAccountAPI.Common; System; System.Collections.Generic; System.Linq; System.Threading.Tasks; System.Timers; namespace PaymentAccountAPI.Helper { <summary> 定时周期帮助类 </summary> TimeCycleHelp : ModelBase { public TimeCycleHelp(ILogger<TimeCycleHelp> logger) : base(logger) { this.Timer = new System.Timers.Timer(); } 服务专属计时器 private System.Timers.Timer Timer; 默认计时器时间间隔1秒(提高计时器开始时间准确度) private double DefaultTimerInterval = 1 * 1000; 设置多个循环周期 private List<TimeCycle> TimeCycleList { ; } 更新一个计时器的计时周期 </summary> <param name="newTimerInterval">新的计时周期</param> <param name="isFirstStart">是否是首次更新计时器周期</param> void UpdateTimeInterval(double newTimerInterval,bool isFirstStart = false) { if (this.Timer != null && newTimerInterval > 0) { this.Timer.Stop(); this.Timer.Interval != newTimerInterval) { this.Timer.Interval = newTimerInterval; } if (isFirstStart) { this.Timer.Elapsed += new System.Timers.ElapsedEventHandler(.ServiceAction); } this.Timer.AutoReset = true; .Timer.Start(); } } 内部辅助方法 <param name="sender"></param> <param name="e"></param> void ServiceAction( sender,ElapsedEventArgs e) { List<TimeCycle> currentTimeCycleList = new List<TimeCycle>(); DateTime now = DateTime.Now; DateTime cycleBeginTime; DateTime cycleEndTime; foreach (TimeCycle timeCycle in .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 == ) { TimeSpan timeSpan = now - cycleBeginTime; bool isCanAction = (int)timeSpan.TotalSeconds % timeCycle.ActionSeconds == 0 ? true : ; (isCanAction) { timeCycle.ActionExecutionTimes++; currentTimeCycleList.Add(timeCycle); } } } else { 不在计时周期内,已执行次数清零 timeCycle.ActionExecutionTimes = ; } } 找到当前循环周期后,执行周期内动作 if (currentTimeCycleList.Count > ) { currentTimeCycleList.ForEach(item =>使用多线程执行任务,让代码快速执行 Task.Run(() => item.Action()); }); } } 开启计时器 <param name="timeCycleArray"></param> void Start(params TimeCycle[] timeCycleArray) { if (timeCycleArray != null && timeCycleArray.Length > this.TimeCycleList == null) { this.TimeCycleList = 100); } this.TimeCycleList = timeCycleArray.ToList(); 设置首次计时器周期(首次动作执行,是在计时器启动后在设置的时间间隔后做出的动作) this.UpdateTimeInterval(this.DefaultTimerInterval,1)">); } } 结束计时器 void Stop() { .Timer.Stop(); } } 计时周期类 TimeCycle { 唯一标识 int ID { 开始时间(误差1秒=取决于计时器默认时间间隔) string BeginTime { 结束时间 string EndTime { 最大执行次数 int MaxActionTimes { 计时周期内执行的动作(动作会在到达开始时间后的) public Action Action { 动作执行时间间隔(秒) int ActionSeconds { 方法执行次数 internal int ActionExecutionTimes { ; } public TimeCycle(int id,Action action,1)">int actionSeconds) : this(id,"00:00:00",action,actionSeconds) { } string beginTime,beginTime,actionSeconds,1)">) { } int actionSeconds,1)">int maxActionTimes) : 23:59:59 基本构造器 <param name="id">唯一标识<param name="beginTime">开始时间<param name="endTime">结束时间<param name="action">要执行的任务<param name="actionSeconds">任务执行时间间隔<param name="maxActionTimes">最大执行次数string endTime,1)">int maxActionTimes) { this.ID = id; this.BeginTime = beginTime; this.EndTime = endTime; this.Action = action; this.ActionSeconds = actionSeconds; this.MaxActionTimes = maxActionTimes; } } } ? 3-webAPI服务封装类:
Microsoft.Extensions.Hosting; PaymentAccountAPI.Helper; PaymentAccountAPI.PaymentAccountHelper; System.Threading; System.Threading.Tasks; PaymentAccountAPI.Hangfire { SyncToCMSService : ModelBase,IHostedService {private TimeCycleHelp _TimeCycleHelp { public SyncToCMSService(ConfigHelper configHelper,TimeCycleHelp timeCycleHelp,ILogger<SyncToCMSService> logger) : (logger,configHelper) {this._TimeCycleHelp = timeCycleHelp; } SyncData() { ...需要执行的任务代码 this.Logger.LogInformation($定时任务:完成{currentDate.ToShortDateString()}的交易记录同步!); } Task StartAsync(CancellationToken cancellationToken) { 定时任务:同步服务已启动...); 正式代码 string syncBeginTime = this.ConfigHelper.GetAppSettingValue(SyncCMSBeginTime); string syncEndTime = SyncCMSEndTimethis._TimeCycleHelp.Start(new TimeCycle(999,syncBeginTime,syncEndTime,1)">this.SyncData,1)">3600,1)">2)); 测试代码 this._TimeCycleHelp.Start(new TimeCycle(999,"12:00:00",() => { this.Logger.LogInformation("test123"); },10,3)); return Task.CompletedTask; } Task StopAsync(CancellationToken cancellationToken) { 同步服务已停止...._TimeCycleHelp.Stop(); Task.CompletedTask; } } } ? 4-在startup.cs添加注册服务:
#region 添加定时任务 services.AddSingleton<TimeCycleHelp>(); services.AddHostedService<SyncToCMSService>(); #endregion ? 5-部署到IIS站点项目时的注意事项(引用下面道友的一段话): ? ? ? ?关于GenericHost的生存周期问题 如果你使用的是控制台启动,则此问题暂时可以忽略。 如果你使用的是站点项目,并且还是通过IIS启动,那么你可能要注意了,因为.net core 的站点自身是有HOST宿主处理,IIS是其上代理,其启动关闭,端口映射等由IIS内部完成。所以其依然受限于IIS的闲置回收影响,当IIS闲置回收时,其后的.Net Host也会被一同关闭,需要有新的请求进来时才会再次启动。不过鉴于当前任务处理已经如此简单,有个取巧的做法,实现一个站点自身的心跳检测任务,IIS默认20分钟回收,任务时间可以设为15分钟(你也可以设置IIS站点回收时间),当然如果你的任务如果没有那么严格的时间要求你也可以不用处理,因为回收后一旦接受到新的请求,任务会再次发起。 ? ? 最后感谢一篇道友的文章:.Net Core 简单定时任务框架封装 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- asp.net – IIS7,SSL和“由于请求实体太大,因此未显示该页面
- asp.net-mvc – ApplicationDbContext – 它在项目中的位置
- 在ASP.NET MVC2创建方法中使用FormCollection的正确方法?
- .net – 扩展自定义成员资格提供程序
- 深入研究 Mini ASP.NET Core(迷你 ASP.NET Core),看看 A
- asp.net-web-api – 如何使用OWIN自动主机的web api来提供i
- asp.net – ObjectCache的“Set”和“Add”有什么区别?
- asp.net – 无法自动进入服务器.无法确定停止位置
- ASP.NET应用程序在3个物理层上
- asp.net-mvc – ASP.NET MVC Route,在控制器之前具有值,没有
- ASP.NET Web API内存中测试中的内部服务器错误
- asp.net-core – 入口点没有合适的“程序”类型
- .net – MVC中的客户端证书颁发者(指纹)
- asp经典 – 早期从经典ASP中的函数返回
- asp.net-mvc – Orchard查询按内容类型BlogPost和
- asp.net – AngularJs 2与ASP.NET 4.5.1
- asp.net-mvc – 在部分视图中传递参数 – MVC3 /
- asp.net – 您在哪里存储数据库连接字符串?
- asp.net – System.Web.Cache,会话级别或应用程序
- asp.net-2.0 – 如何解决ASP.NET“?”应用程序路