How to Have a Loop in a Windows Service Without Using the Timer

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...
//...
}
}

How will i achieve the endless loop without timer/thread in C# windows service?

You will have to do the work on another thread, or the windows service manager will assume your service hasn't started because the OnStart() never returns.

Your third-party library shouldn't work any differently, however the thread may require a different apartment model. Try creating an STA thread (see Starting an STAThread in C#) and seeing if that works, otherwise talk to the creator of the library.

Creating windows service without using timer control

A service does not repeat. It simply starts once, and then runs as long as it is not stopped. If it needs to do repeated tasks, you need to take care of the repeating yourself, in your code.

Of course, you could set up an ugly system with an endless for-loop and a Thread.Sleep(), but the issue there is, when starting a service, Windows expects the OnStart to finish, so it can conclude that the service is started, rather than still starting up. The OnStart function should prepare everything to make the service operations run, but it should not execute these operations itself.

So, the reason the timer is used for that is so the OnStart function can finish correctly, and then after that, periodically, the service operations, in your case the GetFailedProductDetails() function, can be started by the timer.


As for that piece of config, as I said in my comment, a bit of xml is not code. The guide you copied that from has explicitly written programming to read, interpret and apply these settings, to set up a Timer object to make it repeat in the configured intervals. Copying that xml without copying the accompanying code will do nothing to help you.

You can use the config file to set up the interval settings, of course, but then you'll also have to actually write the code to read them. The concept of a repeating service doesn't need such settings, though. You can perfectly program the service with a hardcoded half-hour interval and leave it at that.

Keep a Windows Service running without a timer

A windows service does not need to create a timer to keep running. It can either establish a file watcher Using FileSystemWatcher to monitor a directory or start an asynchronous socket listener.

Here is a simple TPL based listener/responder without needing to dedicate a thread to the process.

private TcpListener _listener;

public void OnStart(CommandLineParser commandLine)
{
_listener = new TcpListener(IPAddress.Any, commandLine.Port);
_listener.Start();
Task.Run((Func<Task>) Listen);
}

private async Task Listen()
{
IMessageHandler handler = MessageHandler.Instance;

while (true)
{
var client = await _listener.AcceptTcpClientAsync().ConfigureAwait(false);

// Without the await here, the thread will run free
var task = ProcessMessage(client);
}
}

public void OnStop()
{
_listener.Stop();
}

public async Task ProcessMessage(TcpClient client)
{
try
{
using (var stream = client.GetStream())
{
var message = await SimpleMessage.DecodeAsync(stream);
_handler.MessageReceived(message);
}
}
catch (Exception e)
{
_handler.MessageError(e);
}
finally
{
(client as IDisposable).Dispose();
}
}

Neither of these need a timer

Infinite while loop in Windows Service

To re-run the query every 40 seconds:

private const string Query = "SELECT * FROM 'reportsetting` order by SendingTime;"

protected override void OnStart(string[] args)
{
_timer = new Timer(40 * 1000); // every 40 seconds
_timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
_timer.Start(); // <- important
}

private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
MySqlConnection con = new MySqlConnection(conn);
MySqlCommand comm = new MySqlCommand(Query, con);
con.Open();
MySqlDataReader dr = comm.ExecuteReader();
while (dr.Read())
{

time = dr["SendingTime"].ToString();

if ((str = DateTime.Now.ToString("HH:mm")).Equals(time))
{

//Execute Function and send reports based on the data from the database.

Thread thread = new Thread(sendReports);
thread.Start();
}
}
}

Something like that.
As Groo mentioned though, you might want to dispose of the connection every time so you don't have that hanging around in memory.

C# Windows Service While loop

The best option is to have a timer System.Timers.Timer in your service.

System.Timers.Timer timer = new System.Timers.Timer();

In the constructor add the handler for the Elapsed event:

timer.Interval = 1000; //miliseconds
timer.Elapsed += TimerTicked;
timer.AutoReset = true;
timer.Enabled = true;

Then in the OnStart method start that timer:

timer.Start();

In the event handler do your work:

private static void TimerTicked(Object source, ElapsedEventArgs e)
{
if (!File.Exists(@"C:\Users\john\logOn\oauth_url.txt"))
return;

//If the file exists do stuff, otherwise the timer will tick after another second.
}

A minimal service class will look somewhat like this:

public class FileCheckServivce : System.ServiceProcess.ServiceBase  
{
System.Timers.Timer timer = new System.Timers.Timer(1000);

public FileCheckServivce()
{
timer.Elapsed += TimerTicked;
timer.AutoReset = true;
timer.Enabled = true;
}

protected override void OnStart(string[] args)
{
timer.Start();
}

private static void TimerTicked(Object source, ElapsedEventArgs e)
{
if (!File.Exists(@"C:\Users\john\logOn\oauth_url.txt"))
return;

//If the file exists do stuff, otherwise the timer will tick after another second.
}
}

Best way to do a task looping in Windows Service

You should have an async method that accepts a CancellationToken so it knows when to stop, calls ProccessSmsQueue in a try-catch block and uses Task.Delay to asynchronously wait until the next time it needs to run:

public async Task DoWorkAsync(CancellationToken token)
{
while (true)
{
try
{
ProccessSmsQueue();
}
catch (Exception e)
{
// Handle exception
}
await Task.Delay(TimeSpan.FromMinutes(10), token);
}
}

You can call this method when your application starts and Task.Wait the returned task before existing so you know it completes and has no exceptions:

private Task _proccessSmsQueueTask;
private CancellationTokenSource _cancellationTokenSource;

protected override void OnStart(string[] args)
{
_cancellationTokenSource = new CancellationTokenSource();
_proccessSmsQueueTask = Task.Run(() => DoWorkAsync(_cancellationTokenSource.Token));
}

protected override void OnStop()
{
_cancellationTokenSource.Cancel();
try
{
_proccessSmsQueueTask.Wait();
}
catch (Exception e)
{
// handle exeption
}
}


Related Topics



Leave a reply



Submit