2

I am trying to use a timer in a windows service. The service is able to start and stop and I write something to the event log when this happens, this works. My problem is that I also want to use a timer that keeps running and write something to event log every time the timeElapsed event is fired.

EDIT: (I changed the code, so the timer is a field, but still not the result I would expect, no log entries in event log)

using System.Timers;

initializing the service:

    public Timer timer;

    public MonitorService()
    {
        InitializeComponent();
        timer = new Timer(10000);
        //Some code that really doesn't matter
    }

The on start event

    protected override void OnStart(string[] args)
    {
        // Hook up the Elapsed event for the timer.
        timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
        timer.Enabled = true;

        timer.Start();

        EventLogger.WriteEntry("Biztalk monitoring service started", EventLogEntryType.SuccessAudit);

        // If the timer is declared in a long-running method, use
        // KeepAlive to prevent garbage collection from occurring
        // before the method ends.
        // GC.KeepAlive(timer);
    }


    private int count =0;

The on timed event: (This is what won't work, there are no entries written to event log every 10 seconds, while I expect it to do)

    // Specify what you want to happen when the Elapsed event is 
    // raised.
    private void OnTimedEvent(object source, ElapsedEventArgs e)
    {
        //Some other code that doesn't mather
        count++;
        EventLogger.WriteEntry(string.Format("TimerEvent has ran {0} times. Total time is: {1}", count, e.SignalTime), EventLogEntryType.Information);
    }

The on stop event:

    protected override void OnStop()
    {
        EventLogger.WriteEntry("Biztalk monitoring service stopped", EventLogEntryType.Warning);
    }

Main

For those who wonder this is my main method in Program.cs:

     ///<summary>
     ///The main entry point for the application.
     ///</summary>
    static void Main()
    {
        var servicesToRun = new ServiceBase[] 
            { 
                new MonitorService() 
            };
        ServiceBase.Run(servicesToRun);
    }

Already asked? Yes indeed!

I am aware of the fact that this question has been asked earlier like here: Windows service with timer AND Best Timer for using in a Windows service

But those solutions doesn't seem to solve my problem.

Any suggestions are welcome!

Community
  • 1
  • 1
Nick N.
  • 10,720
  • 4
  • 50
  • 70
  • 1
    I strongly urge you NOT to use `System.Timers.Timer` because it swallows exceptions, hiding bugs. If an exception occurs in your Elapsed event, you will never know. See http://blog.mischel.com/2011/05/19/swallowing-exceptions-is-hiding-bugs/. You should 1) protect your event handler with a `try/catch`, and 2) use `System.Threading.Timer`. – Jim Mischel May 15 '13 at 12:43
  • @JimMischel I just found out that this was actually my problem and now I see your comment. It was just swallowing an exception and there for it did not work. Does System.Threading.Timer fix this all? – Nick N. May 15 '13 at 12:46
  • `System.Threading.Timer` won't swallow the exception, which will let you know that something is wrong in your handler. The real solution is to be very careful about handling exceptions in your timer event handler. – Jim Mischel May 15 '13 at 12:57
  • Does System.Threading.Timer write something to the event log or how will it let me know exactly when I am not debugging? – Nick N. May 15 '13 at 13:13
  • No, it doesn't write to the event log. But if an exception goes unhandled in your OnTimedEvent method your program will crash, indicating that there's a problem. `System.Timers.Timer`, on the other hand, just squashes the exception and continues as if nothing happened. `System.Threading.Timer` doesn't relieve you from having to handle exceptions. It just doesn't prevent you from finding out when an exception is thrown. – Jim Mischel May 15 '13 at 14:18
  • Thanks a lot, this was a very helpful lesson:) – Nick N. May 15 '13 at 14:20

2 Answers2

5

You timer is local to the OnStart method. It should not be. It should be a field of your service class, so you don't need to cheat the garbage collector using hints.

Edit: You did not specify your usings. Make sure by using Timer you are using System.Timers.Timer, not the System.Windows.Forms.Timer.

nvoigt
  • 61,531
  • 23
  • 73
  • 116
  • Ow yeah, you are right, didn't even noticed that anymore, while focussing on other possibly wrong things! Going to try it! – Nick N. May 15 '13 at 10:50
  • I edited my question with your solution, but it still does not work. – Nick N. May 15 '13 at 11:03
  • I am very sure i'm using that one, I will add it to my question – Nick N. May 15 '13 at 11:24
  • I accepted this one since my problem is solved and this answer stated one of the problems, however please keep in mind that the comment from Jim Mischel is an important one as well! – Nick N. May 15 '13 at 12:48
0

If you want to log something to event log (other than what you are doing in the elapsed event of the timer you are using) after a set period of time, you can use another timer at service level and register its elapsed event. In that event you can log whatever you want.

As mentioned by nvoigt you should move this timer to service level as well.

Ehsan
  • 28,801
  • 6
  • 51
  • 61