Im building my first Windows Service. It's a component that connects to a mailbox and downloads all mails and store them on my local drive.
My questions are these.
What is the best way to repeat a program call in c# windows service. Im thinking of using a simple timer? Where do I start and stop the timer? is it in the service itself or the program my service is running?
What code should be included in a Windows Service for the following function
protected override void OnStart(string[] args)
{
//timer?
// MyProgram mp = new MyProgram();
}
Should I simply start my application with a new instance like above or should I include more stuff?
As I said this is my first time for using Windows Services so.
EDIT:
Thanks for all the answers. There are of course lots of different ways to do this but I found that best way for me is the one mark as a solution.
Thanks for any help!
Here's a template you can use it handles the reentrantcy problems with using a timer.
public partial class Service : ServiceBase{
System.Timers.Timer timer;
public Service()
{
timer = new System.Timers.Timer();
//When autoreset is True there are reentrancy problme
timer.AutoReset = false;
timer.Elapsed += new System.Timers.ElapsedEventHandler(DoStuff);
}
protected override void OnStart(string[] args)
{
timer.Interval = 1;
timer.Start();
}
private void DoStuff(object sender, System.Timers.ElapsedEventArgs e)
{
Collection stuff = GetData();
LastChecked = DateTime.Now;
foreach (Object item in stuff)
{
item.Dosomthing(); //Do somthing should only be called once
}
TimeSpan ts = DateTime.Now.Subtract(LastChecked);
TimeSpan MaxWaitTime = TimeSpan.FromMinutes(5);
if (MaxWaitTime.Subtract(ts).CompareTo(TimeSpan.Zero) > -1)
timer.Interval = MaxWaitTime.Subtract(ts).Milliseconds;
else
timer.Interval = 1;
timer.Start();
}
OnContinue OnPause and OnStop are petty easy to work out.
protected override void OnPause()
{
base.OnPause();
this.timer.Stop();
}
protected override void OnContinue()
{
base.OnContinue();
this.timer.Interval = 1;
this.timer.Start();
}
protected override void OnStop()
{
base.OnStop();
this.timer.Stop();
}
I use AutoResetEvent with a timeout:
while(!autoResetEvent.WaitOne(MY_MILLISECOND_WAIT))
{
// do something
}
And when I want to stop, I simply set on the autoResetEvent
.
Timer is bad for multiple reason one being Reentry.
OnStart(string[] args)
will create the autoResetEvent
.
Here is my implementaion of it as PollingWorker
:
public class PollingWorker : IDisposable
{
private const int DEFAULT_INTERVAL_MS = 1000; // 1 second
private const int WAIT_INTERVAL = 20; // MS
private Thread _labourer = null;
private int _pollingIntervalMS = DEFAULT_INTERVAL_MS;
private ParameterizedThreadStart _work = null;
private bool _working = false;
private object _state = new object();
private AutoResetEvent _resetTimer = new AutoResetEvent(false);
private bool _itsTimeToQuite = false;
private bool _poked = false;
private bool _isCurrentlyWorking = false;
public string Name
{
get { return _labourer.Name; }
set { _labourer.Name = value; }
}
public PollingWorker(int intervalMS, ParameterizedThreadStart work, object state):
this(intervalMS, work, state, Guid.NewGuid().ToString())
{
}
public PollingWorker(int intervalMS, ParameterizedThreadStart work, object state, string name)
{
_pollingIntervalMS = intervalMS;
_labourer = new Thread(new ThreadStart(TryDoingSomeWork));
_labourer.Name = name;
_work = work;
}
public int PollingIntervalMS
{
get { return _pollingIntervalMS; }
set
{
_pollingIntervalMS = value;
}
}
public void StartWork()
{
StartWork(true);
}
public void StartWork(bool initialWait)
{
_working = true;
_poked = !initialWait;
_labourer.Start();
}
public void PauseWork()
{
_working = false;
}
public void Quit()
{
Quit(int.MaxValue);
}
public void Quit(int maximumWaitToFinishCurrentWorkMS)
{
int totalWait = 0;
_itsTimeToQuite = true;
_working = false;
_resetTimer.Set();
while (_isCurrentlyWorking && Thread.CurrentThread.Name != _labourer.Name) // in case Quit is called from Work
{
Thread.Sleep(WAIT_INTERVAL);
totalWait += WAIT_INTERVAL;
if(totalWait>maximumWaitToFinishCurrentWorkMS)
break;
}
Dispose();
}
// poke to wake up !
public void Poke()
{
try
{
// if you call set on the same thread while it is not on waitOne
// it does not work
if (Thread.CurrentThread.Name == this.Name)
//_resetTimer.Set();
_poked = true;
else
_resetTimer.Set();
}
catch
{
// ignore any error with poking
}
}
private void TryDoingSomeWork()
{
while (!_itsTimeToQuite)
{
//Debug.WriteLine(string.Format("{0:ss fff}\t{1}\t{2}\t{3}", DateTime.Now, this.Name, string.Empty, string.Empty));
if (!_poked)
_resetTimer.WaitOne(_pollingIntervalMS, false);
_poked = false;
// timed-out which means timer's pulse, so do some work
if (_working)
{
_isCurrentlyWorking = true;
_work(_state);
_isCurrentlyWorking = false;
}
}
}
public object State
{
get { return _state; }
set
{
lock (_state)
{
_state = value;
}
}
}
public bool Working
{
get { return _working; }
}
#region IDisposable Members
public void Dispose()
{
try
{
_resetTimer.Close();
_labourer.Abort();
}
catch
{
// dont want to raise errors now
// so ignore especially threadabortexception!!
}
}
#endregion
}
Create a thread or something, no need for a timer! In the OnStart you start the thread and in OnStop you can stop the thread.