加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

定时器_在.net core3.0 webapi中添加自定义定时器功能

发布时间:2020-12-16 08:57:57 所属栏目:asp.Net 来源:网络整理
导读:前言:想在.net framework环境使用自定义定时器的话,参考我的另一篇文章:https://www.cnblogs.com/lxhbky/p/10242839.html 想在.net core中使用定时器功能,需要借助一个服务接口:IHostedService,? ?继承并实现对应方法,最后再setup.cs类中添加注册服务

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读