Windows Service System.Timers.Timer未触发

Joe*_*own 31 .net service windows-services timer

我有一个用C#编写的Windows服务,用于每隔几分钟执行一次任务.我正在使用它System.Timers.Timer,但它似乎永远不会发射.我在SO和其他地方查看过很多不同的帖子,我没看到我的代码有什么问题.

这是我的代码,为清楚起见删除了与非计时器相关的项目...

namespace NovaNotificationService
{
    public partial class NovaNotificationService : ServiceBase
    {
        private System.Timers.Timer IntervalTimer;
        public NovaNotificationService()
        {
            InitializeComponent();
            IntervalTimer = new System.Timers.Timer(60000);  // Default in case app.config is silent.
            IntervalTimer.Enabled = false;
            IntervalTimer.Elapsed += new ElapsedEventHandler(this.IntervalTimer_Elapsed);
        }

        protected override void OnStart(string[] args)
        {
            // Set up the timer...
            IntervalTimer.Enabled = false;
            IntervalTimer.Interval = Properties.Settings.Default.PollingFreqInSec * 1000;
            // Start the timer and wait for the next work to be released...
            IntervalTimer.Start();
        }

        protected override void OnStop()
        {
            IntervalTimer.Enabled = false;
        }

        private void IntervalTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {   // Do the thing that needs doing every few minutes...
            DoWork();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我真的在这个问题上摸不着头脑.任何人都可以发现我出错的傻事吗?

编辑: 通过建议,我IntervalTimer.Enabled = true;之前IntervalTimer.Start();在服务OnStart方法中添加.这不能解决问题.

我已经将文件跟踪日志记录添加到服务中以确认一些内部结构,并且我确信在OnStart()完成时Timer.Enabled值为true.

Joe*_*own 48

这是我的解决方法......

经过太多时间寻找答案,我发现了各种各样的文章和博客讨论Windows服务中的计时器.我已经看到了很多关于这方面的意见,它们都分为三类,并按频率降序排列:

  1. 不要使用,System.Windows.Forms.Timer因为它不起作用.(这才有意义)

  2. 不要使用,System.Threading.Timer因为它不起作用,System.Timers.Timer而是使用.

  3. 不要使用,System.Timers.Timer因为它不起作用,System.Threading.Timer而是使用.

在此基础上,我试图2.这也似乎被微软推荐的,因为他们说,该方法System.Timers.Timer适用于"服务器应用程序".

我发现System.Timers.Timer只是在我的Windows服务应用程序中不起作用.因此,我已切换到System.Threading.Timer.这是一个麻烦,因为它需要一些重构才能使它工作.

这大约是我现在的工作代码...

namespace NovaNotificationService
{
    public partial class NovaNotificationService : ServiceBase
    {
        private System.Threading.Timer IntervalTimer;
        public NovaNotificationService()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            TimeSpan tsInterval = new TimeSpan(0, 0, Properties.Settings.Default.PollingFreqInSec);
            IntervalTimer = new System.Threading.Timer(
                new System.Threading.TimerCallback(IntervalTimer_Elapsed)
                , null, tsInterval, tsInterval);
        }

        protected override void OnStop()
        {
            IntervalTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
            IntervalTimer.Dispose();
            IntervalTimer = null;
        }

        private void IntervalTimer_Elapsed(object state)
        {   // Do the thing that needs doing every few minutes...
            // (Omitted for simplicity is sentinel logic to prevent re-entering
            //  DoWork() if the previous "tick" has for some reason not completed.)
            DoWork();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我讨厌"医生,医生,当我这样做时疼痛......"解决方案,但这就是我不得不诉诸的.对于有这个问题的下一个人来说还有一个意见...


Mic*_*aga 10

您忘记通过设置启用计时器:

IntervalTimer.Enabled = true;
Run Code Online (Sandbox Code Playgroud)

或调用Start方法:

IntervalTimer.Start();
Run Code Online (Sandbox Code Playgroud)
protected override void OnStart(string[] args)
{
    // Set up the timer...
    IntervalTimer.Interval = Properties.Settings.Default.PollingFreqInSec * 1000;
    // Start the timer and wait for the next work to be released...
    IntervalTimer.Start();
}
Run Code Online (Sandbox Code Playgroud)


小智 6

显然,System.Timers.Timer会隐藏任何异常,悄悄地吞下它们,然后窒息.当然,您可以在您已添加为计时器的处理程序的方法中处理这些,但是如果在入口处立即抛出异常(在执行第一行代码之前,如果您的方法声明了变量,则会发生这种情况)例如,如果你在一个强名称的DLL中使用了一个你有错误版本的对象,那么你永远不会看到那个异常.

你要和我们一起撕裂你的头发.

或者你可以这样做:

  • 创建一个包装器方法(在try-catch循环中)调用您想要执行的方法.如果这个方法在你身上濒临死亡,那么被包装的方法可以在不杀死计时器的情况下进行异常处理,因为如果你不停止计时器,它将永远不会发现出错的地方.

(我最终停止了计时器,因为如果它失败了,再次尝试对这个特定的应用程序没有任何意义......)

希望这能帮助那些从Google登陆的人(就像我一样).


URB*_*URB 5

我还必须切换到 System.Threading.Timer。为了让重构更容易,让其他人更轻松,我创建了一个单独的类,其中包含 System.Threading.Timer 的一个实例,并具有与 System.Timers.Timer 几乎相同的方法,因此调用代码只需最少的更改:

/// <summary>
/// Custom Timer class, that is actually a wrapper over System.Threading.Timer
/// </summary>
/// <seealso cref="System.IDisposable" />
internal class Timer : IDisposable
{
    System.Threading.Timer _timer;

    public Timer()
    {

    }
    public Timer(int interval) : this()
    {
        this.Interval = interval;
    }

    public bool AutoReset { get; set; }
    public bool Enabled { get; set; }
    public int Interval { get; set; }
    public Action<object> OnTimer { get; internal set; }

    public void Dispose()
    {
        if (_timer != null)
        {
            _timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
            _timer.Dispose();
            _timer = null;
        }
    }

    public void Start()
    {
        _timer = new System.Threading.Timer(
            new System.Threading.TimerCallback(OnTimer), null, 0, Interval);
    }
    public void Stop()
    {
        if (_timer != null)
        {
            _timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我希望这个能帮上忙!