Safely Stopping Windows Services

Here’s yet another post of simple code samples that provides an elegant solution to a common problem.

When it comes to Windows services, I often find myself writing apps that are required to perform a task at a predetermined interval.

Do this every 5 minutes, do that once a day.

It’s very easy for a developer to just create a new Windows service project, spin off a thread in OnStart() and off you go. The problem that this often leads to during maintenance is the apprehension that comes with stopping a service in a production environment. How do I know if my app is actually doing something? Do I look at my logs before stopping the service to make sure I’m not aborting my process in the middle of a transaction?

So here’s a simple BaseWindowsService class that you can inherit from to solve this common problem: run a task at a set interval and give it enough time to complete after a Stop command is issued.

Implementing the Class

To implement the BaseWindowsService class, simply create a new console application project, add a reference to the base service, and create a new class that inherits from it. Implement the constructor and override the DoYourMagic(string[] args) method (which is the code that will get executed at your interval).

stopping_windows_services1

On Program -> Main, just create an instance of your class that inherits from the base service.

stopping_windows_services2

In the app.config file, you can define the interval at which your code will run (ActionSleep) and how long you want to give your application to complete its task before shutting down (StopServiceWait).

stopping_windows_services3

Now let’s set a DEBUG argument on start to run in Debug mode (more on this later). Create a fake task that takes some time to complete and run it.

stopping_windows_services4

stopping_windows_services5

Here’s the service running on debug mode:

stopping_windows_services6

Note how my task runs on its scheduled interval and we actually complete it after the Stop is requested. Once the task completes, the service is stopped safely.

How to Stop the Service Safely

To stop the service, we set a ManualResetEvent for when our task is done running.

The Stop command waits for the ManualResetEvent for the duration specified in the app.config file. Once the wait expires, we force the shutdown.

stopping_windows_services7

stopping_windows_services8

Added Bonuses

Note that the code implements Chad’s Console Application trick for debugging, self-installing, and uninstalling arguments for easy debug and deployment. To run your service as a console app for debugging, execute your service as MyWindowsService.exe DEBUG or add a DEBUG argument to your project properties.

The service also has a self-installing and uninstalling feature. Execute MyWindowsService.exe i to install the service and MyWindowsService.exe u to uninstall the service. The base service uses a basic sc.exe to create and delete for these two functions, and assumes the class name for the service name.

stopping_windows_services9

stopping_windows_services10

Future Enhancements

  • Use a resource file to define the name, users, description, startup mode, and any other Windows service properties.
  • Make this project a NuGet package.

I’ll happily take a pull request!


Related posts