【问题标题】:Windows Service - How to make task run at several specific times?Windows 服务 - 如何使任务在多个特定时间运行?
【发布时间】:2012-04-30 08:20:11
【问题描述】:

我有一个 Windows 服务正在运行。在其中,任务当前每天晚上 7 点运行。 例如,在上午 9.45、上午 11.45、下午 2 点、下午 3.45、下午 5 点和下午 5.45 点运行它的最佳方式是什么。

我知道我可以安排任务来运行该功能,但我想知道如何在我的 Windows 服务中执行此操作。当前代码如下:

private Timer _timer;
private DateTime _lastRun = DateTime.Now;
private static readonly log4net.ILog log = log4net.LogManager.GetLogger
(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

protected override void OnStart(string[] args)
{
    // SmartImportService.WebService.WebServiceSoapClient test = new WebService.WebServiceSoapClient();
    // test.Import();
     log.Info("Info - Service Started");
    _timer = new Timer(10 * 60 * 1000); // every 10 minutes??
    _timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
    _timer.Start();
}

private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    log.Info("Info - Check time");
    DateTime startAt = DateTime.Today.AddHours(19);
    if (_lastRun < startAt && DateTime.Now >= startAt)
    {
        // stop the timer 
        _timer.Stop();               

        try
        {
           log.Info("Info - Import");
           SmartImportService.WebService.WebServiceSoapClient test = new WebService.WebServiceSoapClient();
           test.Import();
        }
        catch (Exception ex) {
           log.Error("This is my error - ", ex);
        }
        _lastRun = DateTime.Now;
        _timer.Start();
   }
}

【问题讨论】:

    标签: c# windows-services


    【解决方案1】:

    如果您不想使用 cron 或石英,请编写一个函数来查找现在和下一次运行之间的时间间隔并相应地重置计时器,在服务启动和 timeelapsed 事件时调用此函数。你可以这样做(代码未经测试)

       System.Timers.Timer _timer;
        List<TimeSpan> timeToRun = new List<TimeSpan>();
        public void OnStart(string[] args)
        {
    
            string timeToRunStr = "20:45;20:46;20:47;20:48;20:49";
            var timeStrArray = timeToRunStr.Split(';');
            CultureInfo provider = CultureInfo.InvariantCulture;
    
            foreach (var strTime in timeStrArray)
            {
                timeToRun.Add(TimeSpan.ParseExact(strTime, "g", provider));
            }
            _timer = new System.Timers.Timer(60*100*1000);
            _timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
            ResetTimer();
        }
    
    
        void ResetTimer()
        {
            TimeSpan currentTime = DateTime.Now.TimeOfDay;
            TimeSpan? nextRunTime = null;
            foreach (TimeSpan runTime in timeToRun)
            {
    
                if (currentTime < runTime)
                {
                    nextRunTime = runTime;
                    break;
                }
            }
            if (!nextRunTime.HasValue)
            {
                nextRunTime = timeToRun[0].Add(new TimeSpan(24, 0, 0));
            }
            _timer.Interval = (nextRunTime.Value - currentTime).TotalMilliseconds;
            _timer.Enabled = true;
    
        }
    
        private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            _timer.Enabled = false;
            Console.WriteLine("Hello at " + DateTime.Now.ToString());
            ResetTimer();
        }
    

    【讨论】:

    • timeToRun 什么时候设置?
    • 我得到错误....System.NullReferenceException:对象引用未设置为对象的实例。在 SmartUploadSyncService.Service1.ResetTimer()
    • 函数跑了一遍又一遍,没用时
    【解决方案2】:

    考虑使用Quartz.netCronTrigger

    【讨论】:

    【解决方案3】:

    如果你清楚它应该运行什么时间表..然后在 timeelapsed 事件中更改计时器的时间间隔,以便它按照时间表运行..我从未尝试过

    【讨论】:

      【解决方案4】:

      我会使用一个后台线程并让它执行一个无限循环来完成你的工作并休眠 15 分钟。服务代码会比使用计时器更简洁。

      请参阅 MSDN 上的 this 文章。

      【讨论】:

        最近更新 更多