Writing a Windows Service with a Cancellation Feature

Summary

I’ve blogged about how to write a windows service before (click here).  In my previous blog post I did not deep-dive into how to handle a cancel request issued by someone who is clicking on the stop button.  In this article, I’m going to expand on the previous article and show how to setup a cancellation token and how to pass this object to another object that can use the cancellation token to determine if it should quit and perform a clean-up.


Using Temp Files

If your windows service uses temp files it’s best to design your code to handle the creation and deletion of temp files in one object using the IDisposable pattern.  For a detailed discussion on how to do an IDisposable pattern you can click here (Implementing IDisposable and the Dispose Pattern Properly).

If you download the sample code, you can find an object named “CreateTempFile”.  This object is an example of an object that creates a temp file.  In this example, that’s all the object does, and you can use it in that fashion, or you can combine the temp file operation with your write stream operation and make sure you dispose of both objects in the Dispose method.  Here’s the CreateTempFile object:

public class CreateTempFile : IDisposable
{
    public string TempFile = “”;

    public CreateTempFile()
    {
        TempFile = Path.GetTempFileName();
    }

    public void Dispose()
    {
        Dispose(true);
    }

    ~CreateTempFile()
    {
        Dispose(false);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (TempFile != “”)
            {
                File.Delete(TempFile);
            }
        }
    }
}

Now you can use this object inside a “using” statement that will guarantee that the temp file will be cleaned up if the program is exited.  Here’s an example of the usage.

using (var dataObject = new CreateTempFile())
{
    // code that uses the temp file here…
}
 


Why am I going on and on about using IDisposable?  One of the problems with writing code is that you have to have a reasonable expectation that your code will be modified some time in the future.  In addition to that fact, your code will, more than likely, be modified by some other software developer.  As the code inside the using statement in the toy example above begins to grow, any future developer might not realize that there was a temp file created and needs to be disposed of.  The developer working on your code might be adding logic to something that requires a “return” statement and they might not delete the temp file.  By using the IDisposable pattern you are guaranteeing that future developers don’t need to worry about deleting the temp file.  No matter what method they use to exit from that using statement, a dispose command will be issued and the temp file will be deleted.


Cancelling a Thread

OK, now it’s time to talk about the use of a cancellation token.  When you execute your code inside a thread, there is the outer thread that is still running and this is the code that will issue a cancel request.  Once a cancel request is issued, it is your thread that is responsible for detecting a cancellation request and performing an orderly exit.  Imagine it like a building full of people working 9 to 5.  Normally, they will enter the building at 9am and they work all day (I’ll assume they all eat in the cafeteria), and then they go home at 5pm.  Now the fire alarm goes off.  When the fire alarm goes off, everybody drops what they are doing and walks to the nearest exit and leaves the building.  The fire alarm is the cancellation token being passed to the thread (workers).

Let’s pretend we don’t know how to handle a cancellation token.  Let’s assume we’re using the code from my previous Windows Service example and we implemented the token using that method.  The method I used in the earlier example works for the example and it will work for any program as long as the thread does not call another object that performs a long operation.  Here’s some sample code:

public class StartingClass
{
    private volatile bool _stopAgent;
    private static StartingClass _instance;

    public static StartingClass Instance
    {
        get 
        { 
            return _instance ?? (_instance = new StartingClass()); 
        }
    }

    private StartingClass()
    {
        _stopAgent = false;
    }

    public bool Stopped { get; private set; }

    public void Start()
    {
        ThreadPool.QueueUserWorkItem(action =>
        {
            while (!_stopAgent)
            {
                // do something here…

                if (!_stopAgent)
                {
                    Thread.Sleep(5 * 1000); // wait 5 seconds
                }
            }

            Stopped = true;

        }, TaskCreationOptions.LongRunning);
    }

    public void Stop()
    {
        _stopAgent = true;
    }
}

In the sample code above, there is a _stopAgent variable that is initialized to false when the object is created.  The main thread creates this object, then it will initiate the thread by calling the “Start()” method.  If the main thread wants to stop the inner thread, then it will use the “Stop()” method, which sets the _stopAgent variable to true and is detected by the long running inner thread (in the while statement).  The while statement will drop out and set the “Stopped” property to true.  The “Stopped” property’s sole purpose is to be read by the master thread to determine if the inner thread has stopped what it is doing.  Then the master thread can exit the program.  Here’s the master thread of the service object:

public partial class Service1 : ServiceBase
{
    public Service1()
    {
        InitializeComponent();
    }

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

    protected override void OnStop()
    {
        StartingClass.Instance.Stop();

        while (!StartingClass.Instance.Stopped)
        {
            // wait for service to stop
        }
    }
}

I added the wait for stop code to the “OnStop()” method.  This will allow the inner thread time to complete its operation and exit clean.

There is a weakness with this logic and that weakness reveals itself if you create an object inside your thread and call a long running method inside that object.  The object cannot access the _stopAgent flag and you can’t just pass the flag to the object (because it will only contain the initial false value when it was passed).  You could pass a reference to this value and then it will change when a cancel request is made, but only within the method it is passed to.  There is an easier way…


Using a Cancellation Token

If you download the sample code that goes along with this blog post (see link at bottom), you’ll notice that I have refactored the windows service to use an object called CancellationTokenSource.  The new StartingClass object looks like this:

public class StartingClass
{
    private static StartingClass _instance;
    public CancellationTokenSource cts = new  

           CancellationTokenSource();

    public static StartingClass Instance
    {
        get 
       
            return _instance ?? (_instance = new StartingClass()); 
        }
    }

    public bool Stopped { get; private set; }

    public void Start()
    {
        ThreadPool.QueueUserWorkItem(new WaitCallback(action =>
        {
            CancellationToken token = (CancellationToken)action;
            while (!token.IsCancellationRequested)
            {
                var dataProcessingObject = new 
                        DataProcessingObject(action);
                dataProcessingObject.PerformProcess();

                if (!token.IsCancellationRequested)
                {
                    Thread.Sleep(5 * 1000); // wait 5 seconds
                }
            }

            Stopped = true;

        }), cts.Token);    }

    public void Stop()
    {
        cts.Cancel();
    }
}

As you can see in the above code, I have replaced the boolean value of_stopAgent with the new “cts” variable.  The “action” object is passed in to the DataProcessingObject as a constructor.  The DataProcessingObject class looks like this:

public class DataProcessingObject
{
    private CancellationToken token;

    public DataProcessingObject(object action)
    {
        token = (CancellationToken)action;
    }

    public void PerformProcess()
    {
        // do something here
        using (var dataObject = new CreateTempFile())
        {
            using (StreamWriter writer = new StreamWriter(dataObject.TempFile, true))
            {
                for (int i = 0; i < 5000; i++)
                {
                    writer.WriteLine(“Some test data“);

                    // check for cancel signal
                    if (token.IsCancellationRequested)
                    {
                        return;
                    }

                    // this is not necessary (only for this demonstration
                    // to force this process to take a long time).

                    Thread.Sleep(1000);
                }
            }
        }
    }
}

A new CancellationToken is created inside the DataProcessingObject.  This will receive the cancellation request from the calling method from the action object.  Inside the DataProcessingObject, the “IsCancellationRequested” boolean flag must be watched to determine if a long running process must end and exit the object.  This will provide a clean exit (due to the fact that the CreateTempFile() object will be exited before the program shuts down and delete any temp files created.

Download the Code

You can go to my github account and download the entire working example by clicking here.



 
 

 

Creating a Windows Service Application

Summary

In this post, I’m going to show you the easiest way to get a service application up and running.  Windows Services can be used to perform background tasks while your computer or server continues to perform normal tasks.  Services can also run while a computer is logged out.


Getting Started

The first thing I do when I design a service application is separate the service part from the core code.  I also provide a method of testing my code while not in a service, so I can get feedback on a console screen and put breakpoints in the code instead of trying to read log files and reverse-engineer what is wrong with my program.

So step 1 is to setup a solution with three projects in it.  The first project is the core project itself.  This will be a C# library project and will all of the code that my program will use for it’s functions.  The second project will be a console application.  This application will do nothing more than call the entry program of the core project.  This console application will be used to troubleshoot issues.  The last project will be the service application.  This project will contain the service code plus an installer.  The service application does no more than the console application, call the entry program of the core project.  (see project selector below):



Don’t forget to set your console application as the default startup application (Right-click, select “Set as StartUp Project”).


Setting up the Installer


Technically, you don’t need an installer for your service, you can just manually install your program from powershell.  However, it is much easier to create an installer and then create a powershell script to check if the service is installed, and run your installer if it is not.  To add an installer, open your service project and double-click on the file named “Service1.cs” (assuming you left it the default file name).  You’ll be on a blank designer window.  Right-click on the designer window background and you’ll see this menu:


You should see something like this:



Select “Add Installer” and another file will appear in your project.  The default name is “ProjectInstaller.cs”.  Now expand the file by clicking on the triangle next to the “ProjectInstaller.cs” file and double-click on the file named “ProjectInstaller.Designer.cs”.  Open the region named “Component Designer Generated Code” where we can add a few lines of code.  The following snap shot highlights the added lines of code:



Connecting the Console and Service Applications to Core

Inside your console application, right-click on “References” and add the solution core.  Inside your services application, do the same, right-click on “References” and add the solution core.  Now you have to add the proper “using” statement at the top of your console application “Program.cs” file and add the “using” statement to your service application (called the “Service1.cs” file, right-click on Service1.cs and select “View Code”) so your console and service applications can reference the core project.


Writing Your Core Application

Now we need to create a starting program cs file, I’ll call it “StartingClass.cs” which is the beginning of the program.  Here’s the program shell:

public class StartingClass
{
    private volatile bool _stopAgent;
    private static StartingClass _instance;

    public static StartingClass Instance
    {
        get { return _instance ?? (_instance = new StartingClass()); }
    }

    private StartingClass()
    {
        _stopAgent = false;
    }

    public bool Stopped { get; private set; }

    public void Start()
    {
        ThreadPool.QueueUserWorkItem(action =>
        {
            while (!_stopAgent)
            {
                // do something here
                using (StreamWriter writer = new StreamWriter(“c:\TestService.txt“, true))
                {
                  writer.WriteLine(“Service is running ” + DateTime.Now.ToString(“H:mm:ss“));
                }

                if (!_stopAgent)
                {
                    Thread.Sleep(5 * 1000); // wait 5 seconds
                }
            }

            Stopped = true;

        }, TaskCreationOptions.LongRunning);
    }

    public void Stop()
    {
        _stopAgent = true;
    }
}

You’ll have to add “usings” for these three dlls:

using System.Threading.Tasks;
using System.Threading;
using System.IO;


The first thing that this object does is provide a static instance.  This is just for convenience.  The constructor initializes the _stopAgent value to false.  This will be set by the calling program (either the console when the user hits a key or the service when someone clicks the service stop button).  The “Start()” method is the guts of this program.  This is wrapped in a threadpool so that your service doesn’t get hung when you start it up.  The service will kick off your program and then continue on it’s way (which we will program to remain idle).  Inside the threadpool is your program’s main loop.  You can process something inside this loop (calling other classes if necessary) until the service is stopped.  For this little sample, I’m just going to keep appending the current time to a text file on the C: drive every 5 seconds.


Your Console Application

Let’s get the console application together so we can test the code before moving on to the actual service application.  The code for your console application should pretty much always look like this:

static void Main(string[] args)
{
    StartingClass.Instance.Start();

    Console.WriteLine(“Press any key to gracefully stop the processing…“);
    Console.ReadKey();
    StartingClass.Instance.Stop();

    Console.WriteLine(“Processing stopped. Press any key to exit…“);
    Console.ReadKey();
}

 Now run your console application and see what happens.  First, you’ll see the console screen appear and wait for input to stop.  If you navigate to your C: drive and find the “TestService.txt” file, you can open it and see the time inside.  If you close it and re-open it after 5 seconds have elapsed, you’ll another time appended to the file.  This will continue until you stop your console application.


Your Service Application

Now go to your service application.  Find “Service1.cs”, right-click on it and “View Code”.  You will see an OnStart() and an OnStop() method inside the main class.  You will call your start() method from the OnStart() and call your stop method inside your OnStop() method.  Yes, it’s that easy.


The Powershell Installation Script

Here’s the script to install or re-install your service (name it powershellscript.ps1):

#If service is installed, stop it; else install it.
$serviceFullPath = “path_to_service_exe_fileBlogServiceSample.exe”

Write-Host “Installing service…” -foregroundcolor cyan

Invoke-Command -ScriptBlock { C:WINDOWSMicrosoft.NETFrameworkv4.0.30319InstallUtil.exe /install “$serviceFullPath”}
}

Write-Host “Starting MyService service…” -foregroundcolor cyan
Start-Service MyService

Write-Host “Deployment Complete!” -foregroundcolor Green

You’ll have to navigate to the path of our service executable and paste it into the script above (you can download the file and change the path name).  Then you’ll have to start up powershell.  Run powershell as an administrator:


If you’ve never run powershell before, you’ll probably have to run a command to make it override the system script safety.  Otherwise you’ll get a message indicating that your script cannot be loaded because the execution of scripts is disabled on this system…etc. etc.

So Run the following command:

set-executionpolicy remotesigned

Then run your script:

./powershellscript.ps1

and you should see something like this:



Obviously, the path to your source will be different from mine, but the end of your script should produce the same “Deployment Complete!” message.


Verify Your Service is Running

Go to your control panel -> System and Security -> Administrative Tools  and double-click on “Services”.  You should be able to scroll down and find a service called “MyServiceDisplay”.  Now you know where that is set in your program (inside the ProjectInstaller.cs file).  If you double-click on that line, you’ll see that your service is already started and the service name is “MyService”.  Now go to your C: drive and you should see a text file named “TestService.txt”.  Open this file and you’ll see new time entries.  Close and open this file and additional time entries should appear at 5 second intervals.  Cool eh?


Stopping Your Service

Go back to the Services control panel and double-click on “MyServiceDisplay” and you’ll see the properties window:


Click the “Stop” button and your service should stop.  Check your text file and make sure no more times are appearing.  You have verified that your service works.

If you change your program, you will need to manually stop your service, re-build your application, then manually restart your service.  If you are creating a deployment script you’ll want to make your script stop the service (if it is already installed) copy the exe file over the existing one and then restart the service.  If you want to be safe and provide a roll-back capability, you’ll need to stop your service, copy your new exe into a new directory every time, then change the path of the service to point to the new service and start it back up. I’ll leave that for another blog post.


Deleting a Service

Open a command window (Start menu, type in “CMD”), then type in:

sc delete MyService

You should see a confirmation message:

[SC] DeleteService SUCCESS



Source Code:


BlogServiceSample.zip
powershellscript.zip