How Can a Windows Service Start a Process When a Timer Event Is Raised

C# Timer Elapsed Not Running Batch Process in Windows Service

Windows services run from a separate session with a different desktop so your service will not be able to take an screenshot of your desktop (at least not without a lot of work).

You'll have to either run this as a scheduled task or as a program that runs on startup.

Best Timer for using in a Windows service

Both System.Timers.Timer and System.Threading.Timer will work for services.

The timers you want to avoid are System.Web.UI.Timer and System.Windows.Forms.Timer, which are respectively for ASP applications and WinForms. Using those will cause the service to load an additional assembly which is not really needed for the type of application you are building.

Use System.Timers.Timer like the following example (also, make sure that you use a class level variable to prevent garbage collection, as stated in Tim Robinson's answer):

using System;
using System.Timers;

public class Timer1
{
private static System.Timers.Timer aTimer;

public static void Main()
{
// Normally, the timer is declared at the class level,
// so that it stays in scope as long as it is needed.
// If the timer is declared in a long-running method,
// KeepAlive must be used to prevent the JIT compiler
// from allowing aggressive garbage collection to occur
// before the method ends. (See end of method.)
//System.Timers.Timer aTimer;

// Create a timer with a ten second interval.
aTimer = new System.Timers.Timer(10000);

// Hook up the Elapsed event for the timer.
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

// Set the Interval to 2 seconds (2000 milliseconds).
aTimer.Interval = 2000;
aTimer.Enabled = true;

Console.WriteLine("Press the Enter key to exit the program.");
Console.ReadLine();

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

// Specify what you want to happen when the Elapsed event is
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}
}

/* This code example produces output similar to the following:

Press the Enter key to exit the program.
The Elapsed event was raised at 5/20/2007 8:42:27 PM
The Elapsed event was raised at 5/20/2007 8:42:29 PM
The Elapsed event was raised at 5/20/2007 8:42:31 PM
...
*/

If you choose System.Threading.Timer, you can use as follows:

using System;
using System.Threading;

class TimerExample
{
static void Main()
{
AutoResetEvent autoEvent = new AutoResetEvent(false);
StatusChecker statusChecker = new StatusChecker(10);

// Create the delegate that invokes methods for the timer.
TimerCallback timerDelegate =
new TimerCallback(statusChecker.CheckStatus);

// Create a timer that signals the delegate to invoke
// CheckStatus after one second, and every 1/4 second
// thereafter.
Console.WriteLine("{0} Creating timer.\n",
DateTime.Now.ToString("h:mm:ss.fff"));
Timer stateTimer =
new Timer(timerDelegate, autoEvent, 1000, 250);

// When autoEvent signals, change the period to every
// 1/2 second.
autoEvent.WaitOne(5000, false);
stateTimer.Change(0, 500);
Console.WriteLine("\nChanging period.\n");

// When autoEvent signals the second time, dispose of
// the timer.
autoEvent.WaitOne(5000, false);
stateTimer.Dispose();
Console.WriteLine("\nDestroying timer.");
}
}

class StatusChecker
{
int invokeCount, maxCount;

public StatusChecker(int count)
{
invokeCount = 0;
maxCount = count;
}

// This method is called by the timer delegate.
public void CheckStatus(Object stateInfo)
{
AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
Console.WriteLine("{0} Checking status {1,2}.",
DateTime.Now.ToString("h:mm:ss.fff"),
(++invokeCount).ToString());

if(invokeCount == maxCount)
{
// Reset the counter and signal Main.
invokeCount = 0;
autoEvent.Set();
}
}
}

Both examples comes from the MSDN pages.

Use of Timer in Windows Service

Firstly, pick the right kind of timer. You want either System.Timers.Timer or System.Threading.Timer - don't use one associated with a UI framework (e.g. System.Windows.Forms.Timer or DispatcherTimer).

Timers are generally simple

  1. set the tick interval
  2. Add a handler to the Elapsed event (or pass it a callback on construction),
  3. Start the timer if necessary (different classes work differently)

and all will be well.

Samples:

// System.Threading.Timer sample
using System;
using System.Threading;

class Test
{
static void Main()
{
TimerCallback callback = PerformTimerOperation;
Timer timer = new Timer(callback);
timer.Change(TimeSpan.Zero, TimeSpan.FromSeconds(1));
// Let the timer run for 10 seconds before the main
// thread exits and the process terminates
Thread.Sleep(10000);
}

static void PerformTimerOperation(object state)
{
Console.WriteLine("Timer ticked...");
}
}

// System.Timers.Timer example
using System;
using System.Threading;
using System.Timers;
// Disambiguate the meaning of "Timer"
using Timer = System.Timers.Timer;

class Test
{
static void Main()
{
Timer timer = new Timer();
timer.Elapsed += PerformTimerOperation;
timer.Interval = TimeSpan.FromSeconds(1).TotalMilliseconds;
timer.Start();
// Let the timer run for 10 seconds before the main
// thread exits and the process terminates
Thread.Sleep(10000);
}

static void PerformTimerOperation(object sender,
ElapsedEventArgs e)
{
Console.WriteLine("Timer ticked...");
}
}

I have a bit more information on this page, although I haven't updated that for a long time.

Timer behavior when execution takes longer than span?

It'll call it again on another thread.

Depending on the nature of the operation you will want to either:

  1. Ignore this, if the code called is safe for multiple simultaneous calls then this may be fine. Of course, you have to know that it's fine.
  2. Lock on the timer-triggered operation. Be aware that you can end up with a queue of lots of pending operations, which is very bad.
  3. Lock on the timer-triggered operation, try to obtain the lock with a timeout of zero and if you fail then skip it - there's a thread still here from the last time.
  4. Have the timer as a one-off timer that you restart at the end of each call.

How to have a loop in a Windows service without using the Timer

There's another way to get timed execution, the WaitHandle.WaitOne() method provides a timeout argument. That works very nicely in a service as it lets you implement the need to stop the service and periodic execution in a single method call. The template looks like this:

    Thread Worker;
AutoResetEvent StopRequest = new AutoResetEvent(false);

protected override void OnStart(string[] args) {
// Start the worker thread
Worker = new Thread(DoWork);
Worker.Start();
}
protected override void OnStop() {
// Signal worker to stop and wait until it does
StopRequest.Set();
Worker.Join();
}
private void DoWork(object arg) {
// Worker thread loop
for (;;) {
// Run this code once every 10 seconds or stop right away if the service
// is stopped
if (StopRequest.WaitOne(10000)) return;
// Do work...
//...
}
}

Timer in Windows Service not firing ElapsedEventHandler

From comments on the question you say you are calling it like this:

#if (!DEBUG) 
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new LabelLoader() };
ServiceBase.Run(ServicesToRun);
#else
LabelLoader ll = new LabelLoader();
ll.Start();
#endif

If you are in debug mode that means your main method is this:

    LabelLoader ll = new LabelLoader(); 
ll.Start();

This means that once it has run these two lines the program finishes running and presumably exits. It doesn't matter what your timer is up to, the program has quit and thus your timer never fires.

I'd advise testing your ll with a better harness. Personally I use a winform type interface and just have a start button to mimic the service start (which will then have your code in the button click). Once I think I have that code running as I want I then test it in a service environment.



Related Topics



Leave a reply



Submit