darrylbraaten.com

Software Development and System Architecture

 

Welcome to darrylbraaten.com Sign in | Join | Help
in Search

Darryl's Homepage

Random Ramblings

How to write a windows service using C# and Dot Net

The purpose of this post is to talk about writing a simple windows service.  Most of the examples I have found just talk about the code that gets output when you create a Windows Service project in the IDE.  Where all the example fall down is they get to this bit of code
/// <summary>
/// Set things in motion so your service can do its work.
/// </summary>
protected override void OnStart(string[] args)
{
 // TODO: Add code here to start your service.
}

And just throw in some event log writing to the TODO section.  What they leave out is that the OnStart method needs to complete it's execution in under 30 seconds or the Service Control Manager (SCM) will terminate it.  The OnStart method is really meant to just launch a worker thread that does the work that the service is supposed to do. 

The complimentary method to OnStart is OnStop.  OnStop is executed when the SCM wants to shut down your service.  It has the same rules and OnStart, in that it has 30 seconds to shut down the service before its execution is stopped.

protected override void OnStop()
{
 // TODO: Add code here to perform any tear-down necessary to stop your service.
}

I am going to go over one way to start up a thread on a class that will do the work of the service,  this is where I will put the cheesy EvenLog writing code.  Since services are a pain to debug I will also go over the way that I like to create a tester shell for the service so you don't need to worry so much about debugging a running service. 

To start this how to create a new windows service project in the VS.NET IDE.  This will give you a project with two files a standard AssemblyInfo.cs and a file named Service1.cs

Now add a second project to the solution this will hold the class that does the work.  I will call it the WorkerLibrary, the project will be a Class Library project. Delete Class1.cs that gets created, then add a new class "WorkerClass"

To the WorkerClass we will add a class variable named mStop and a Set accessor
bool mStop = false;
public bool Stop
{
 set
 {
  this.mStop = value;
 }
}

And a method that will do the work
public void DoWork()
{
 while(!mStop)
 {
  //do Work
 }
}

The method will run until the variable mStop is set to true. Now to flesh out the method with the event logging and a little sleep so we don't spam the event log to much.
public void DoWork()
{
 // Create an EventLog instance and assign its source.
 EventLog myLog = new EventLog();
 myLog.Source = "MySource";
 while(!mStop)
 {
  //do Work
  myLog.WriteEntry("Writing to event log.");
  Thread.Sleep(1000);
 }
}

Before we start on the service we need to test if the class we wrote to do this lets add another project to the solution this project will be a standard console application, call it the WorkerTester.  Add the WorkerLibrary as a reference to the new project and add a call to do work in the Main method.
[STAThread]
static void Main(string[] args)
{
 WorkerLibrary.WorkerClass wc = new WorkerLibrary.WorkerClass();
 wc.DoWork();
}

Set the project as the startup project so you can run it. Put a break point on the creation of the WorkerClass object.  Step into DoWork once past the writing to the event log check the event log and make sure you can see an event written.  Now stop the debugger. 

Now that the guts of our simple service are known to be working we can getting to writing the important bits and fill in the TODOs.

Here is the fleshed out OnStart Method

protected override void OnStart(string[] args)
{
 mWorkerClass = new WorkerLibrary.WorkerClass();
  
 mWorkerThread = new Thread(new ThreadStart(mWorkerClass.DoWork));
 mWorkerThread.Start();
}

It just creates an instance of the WorkerClass sets the DoWork methods as the start method for a thread and starts the thread running. mWorkerClass and mWorkerThread are defined at the class level as we need to be able to call there methods from OnStop.

OnStop is a little bit harder to write as there is a bit more going on.  First we have to make sure the service is started, if it is we can attempt to shut it down. 

protected override void OnStop()
{
 if(mWorkerClass != null && mWorkerThread != null)
 {
  mWorkerClass.Stop = true; //tell the DoWork Method to stop
  if(mWorkerThread.Join(1200)) //join returns true if the thread has stopped.
  {
   mWorkerThread = null;
   mWorkerClass = null;
  }
  else
  {//thread is taking to long to exit
   mWorkerThread.Abort(); // kill the thread
   if(mWorkerThread.Join(1000)) // Wait a bit for it to die.
   {
    mWorkerThread = null;
    mWorkerClass = null;
   }
  }
 }
}

There are a couple bit in the OnStop method that will need adjusting depending on what your service is actually doing.  Most important is the time to wait for the Join after letting the DoWork Method know we want to stop.  In this example it is set to 1200 millisecond because that is 200 milliseconds longer then the sleep in the thread.  You will need to use some value that make sense for your application.  You may also want to try a more controlled shutdown possibly looping on a join a few times before just aborting the thread.   Just remember you have about 30 seconds for OnStop to finish before the SCM shuts it down.

A few more quick steps before we can run our service.  Go  to the design view of the Service1 class and look at the properties page.  There is a link there that says Add Installer, click on that link.  This will create a project installer class file allowing us to install the service. Compile the service.  Open a command prompt and change into the directory that the service was compiled into now execute installutil on the exe.
Installutil ExampleWindowsService.exe 
You will need to provide a user name and password for the service to run under.  Once this is done you can load up the service control panel and start the service.  You should see a message telling you that your service has started in the event log and the entries that are created every second.  Now stop your service to stop the event log spam.

To uninstall your service use
Installutil ExampleWindowsService.exe  /u

Source Code

I hope that this is useful if you have any feed back for me leave a comment.  If I find issues with the frame work I will make corrects to this post.

Published Saturday, June 04, 2005 2:17 PM by darryl
Filed under:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

Duncan Campbell said:

Interesting article - i've been kneck-deep in Objective-C (nasty syntax!) for the last couple of months, and it gives me a cosy feeling to see the old c# readability...

What are you up to these days? Sarah and I will be coming back to Van Aug 2006 for a brief visit, so a beverage or two should be the order of the day....

Cheers,

D.
June 8, 2005 11:46 PM
 

Darryl said:

I am doing some work back at BOBJ. I just can't seem to keep away. Interesting project anyway. :)
June 13, 2005 7:21 PM

Leave a Comment

(required) 
(optional)
(required) 
Submit