C# 在指定时间运行功能的 Windows 服务

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19151363/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 14:15:06  来源:igfitidea点击:

Windows Service to run a function at specified time

c#timerwindows-services

提问by Ziyad Ahmad

I wanted to start a Windows service to run a function everyday at specific time.

我想启动一个 Windows 服务来每天在特定时间运行一个功能。

What method i should consider to implement this? Timer or using threads?

我应该考虑什么方法来实现这个?定时器还是使用线程?

采纳答案by Settapon H

(1) On first start, Set _timer.Interval to the amount of milliseconds between the service start and schedule time. This sample set schedule time to 7:00 a.m. as _scheduleTime = DateTime.Today.AddDays(1).AddHours(7);

(1) 在第一次启动时,将 _timer.Interval 设置为服务启动和计划时间之间的毫秒数。此示例将计划时间设置为上午 7:00 作为 _scheduleTime = DateTime.Today.AddDays(1).AddHours(7);

(2) On Timer_Elapsed, reset _timer.Interval to 24 hours (in milliseconds) if current interval is not 24 hours.

(2) 在 Timer_Elapsed 上,如果当前间隔不是 24 小时,则将 _timer.Interval 重置为 24 小时(以毫秒为单位)。

System.Timers.Timer _timer;
DateTime _scheduleTime; 

public WinService()
{
    InitializeComponent();
    _timer = new System.Timers.Timer();
    _scheduleTime = DateTime.Today.AddDays(1).AddHours(7); // Schedule to run once a day at 7:00 a.m.
}

protected override void OnStart(string[] args)
{           
    // For first time, set amount of seconds between current time and schedule time
    _timer.Enabled = true;
    _timer.Interval = _scheduleTime.Subtract(DateTime.Now).TotalSeconds * 1000;                                          
    _timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
}

protected void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    // 1. Process Schedule Task
    // ----------------------------------
    // Add code to Process your task here
    // ----------------------------------


    // 2. If tick for the first time, reset next run to every 24 hours
    if (_timer.Interval != 24 * 60 * 60 * 1000)
    {
        _timer.Interval = 24 * 60 * 60 * 1000;
    }  
}

Edit:

编辑:

Sometimes people want to schedule the service to start at day 0, not tomorrow so they change DateTime.Today.AddDays(0).If they do that and set a time in the past it causes an error setting the Interval with a negative number.

有时人们希望将服务安排在第0天而不是明天开始,所以他们会改变DateTime.Today.AddDays(0)。如果他们这样做并设置过去的时间,则会导致将 Interval 设置为负数的错误。

//Test if its a time in the past and protect setting _timer.Interval with a negative number which causes an error.
double tillNextInterval = _scheduleTime.Subtract(DateTime.Now).TotalSeconds * 1000;
if (tillNextInterval < 0) tillNextInterval += new TimeSpan(24, 0, 0).TotalSeconds * 1000;
_timer.Interval = tillNextInterval;

回答by Ian Mercer

Use Windows built in Task Scheduler (http://windows.microsoft.com/en-us/windows7/schedule-a-task) or Quartz.net.

使用 Windows 内置的任务计划程序 ( http://windows.microsoft.com/en-us/windows7/schedule-a-task) 或 Quartz.net。

Unless ... you have a service that's doing lots of other processing and needs to be running all the time in which case a Timer might be appropriate.

除非......您有一个服务正在执行许多其他处理并且需要一直运行,在这种情况下 Timer 可能是合适的。

回答by Jakub Szu?akiewicz

Are you sure, you need a service, that runs only one time per day?

您确定需要一项每天仅运行一次的服务吗?

Maybe Windows Task Schedule will be better solution?

也许 Windows 任务计划会是更好的解决方案?

回答by Evan

Good answer (I used your code), but one problem with this line:

很好的答案(我使用了你的代码),但这一行有一个问题:

_timer.Interval = _scheduleTime.Subtract(DateTime.Now).TotalSeconds * 1000;

If DateTime.now is later than scheduleTime, you will go negative and this will generate an exception when assigning to timer.Interval.

如果 DateTime.now 晚于 scheduleTime,您将变为负值,这将在分配给 timer.Interval 时产生异常。

I used:

我用了:

if (DateTime.now > scheduleTime)
    scheduleTime = scheduleTime.AddHours(24);

Then do the subtraction.

然后做减法。

回答by Binish Babu

private static double scheduledHour = 10;
private static DateTime scheduledTime;

public WinService()
{
     scheduledTime = DateTime.Today.AddHours(scheduledHour);//setting 10 am of today as scheduled time- service start date
}

private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
      DateTime now = DateTime.Now;
      if (scheduledTime < DateTime.Now)
      {
         TimeSpan span = now - DateTime.Now;
         scheduledTime = scheduledTime.AddMilliseconds(span.Milliseconds).AddDays(1);// this will set scheduled time to 10 am of next day while correcting the milliseconds
         //do the scheduled task here
      }  
}

回答by drowa

You can do it with a thread and an event; a timer is not necessary.

你可以用一个线程和一个事件来完成;不需要计时器。

using System;
using System.ServiceProcess;
using System.Threading;

partial class Service : ServiceBase
{
    Thread Thread;

    readonly AutoResetEvent StopEvent;

    public Service()
    {
        InitializeComponent();

        StopEvent = new AutoResetEvent(initialState: false);
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            StopEvent.Dispose();

            components?.Dispose();
        }

        base.Dispose(disposing);
    }

    protected override void OnStart(string[] args)
    {
        Thread = new Thread(ThreadStart);

        Thread.Start(TimeSpan.Parse(args[0]));
    }

    protected override void OnStop()
    {
        if (!StopEvent.Set())
            Environment.FailFast("failed setting stop event");

        Thread.Join();
    }

    void ThreadStart(object parameter)
    {
        while (!StopEvent.WaitOne(Timeout(timeOfDay: (TimeSpan)parameter)))
        {
            // do work here...
        }
    }

    static TimeSpan Timeout(TimeSpan timeOfDay)
    {
        var timeout = timeOfDay - DateTime.Now.TimeOfDay;

        if (timeout < TimeSpan.Zero)
            timeout += TimeSpan.FromDays(1);

        return timeout;
    }
}

回答by Pouriya Ghasemi

if it is one in a day, why you don't use task scheduler? windows service is useful when you want run task many time in minute. so if you want to run a program in a specific time, its better to use task scheduler and set event of task scheduler on a specific time in day. I do many thing with task scheduler and its perfect. you can set rout of program in task scheduler and set interval time to run it. if you want to run a program every 5 min in a day still you can use task scheduler and its better way.

如果是一天一个,为什么不使用任务计划程序?当您希望在几分钟内多次运行任务时,windows 服务很有用。因此,如果您想在特定时间运行程序,最好使用任务调度程序并在一天中的特定时间设置任务调度程序的事件。我用任务调度程序做了很多事情,它很完美。您可以在任务调度程序中设置程序的路由并设置运行它的间隔时间。如果您想每天每 5 分钟运行一个程序,您仍然可以使用任务调度程序及其更好的方法。