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).
On Program -> Main, just create an instance of your class that inherits from the base service.
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).
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.
Here’s the service running on debug mode:
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.
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.
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!