Creating easy to debug Windows Services in .NET

When you want a process to run continuously, even when no user is logged in to a machine and when you want that process to start running as soon as Windows does, you may want to create a Windows Service.

Using .NET’s System.ServiceProcess namespace you can easily write code that allows your program to act as a Windows Service. The namespace also includes classes that let you manage services, such as starting, stopping and installing them.

Creating a basic Windows Service

When using the Visual Studio template for a “Windows Service Application”, a project will be created that shows the basic skeleton. This is easily recreated:

However, if you now hit F5, you’ll get an error saying “Cannot start service from the command line or a debugger. A Windows Service must first be installed […].”:

Attaching the debugger

The MSDN way to debug a service is pretty convoluted: you’ll have to install the service, start it and attach Visual Studio’s debugger to the service process. And then when you spot an issue and fix it, you’ll have to perform the mentioned steps again.

Now when you hit F5 (which automatically attaches the debugger to your process), you’re debugging your service logic! This is the simplest and least invasive way making it possible to debug a Windows Service without installing it and attaching the debugger.

However, you preferably want extract the service logic and do your debugging on that class. This way you can reuse the base class among your projects and you improve testability.

In order to support more options than just debugging, we also support command line arguments:

When you start the executable without arguments, it will try to run as a Windows Service. This is recommended because when installed as a service, by default it will also be started without arguments. Unless specified otherwise in its image path of course, so it is possible to reverse this behavior by installing it for example using a “/RunService” parameter.

Now when providing the “/D” or “/DEBUG” flag, the instantiated MyServiceLogic with have its Start() method called. You can set the command line arguments by right-clicking the console app project in Visual Studio, selecting Properties and clicking the Debug tab:

Note: the call to myServiceLogic.Start() passes the remainder of the command line arguments (omitting the “/D[EBUG]”), so your service logic can also support other parameters. A starting service does not receive its commandline arguments at OnStart() nor in Main() though, the parameters you receive there are those entered in the “Start parameters” set in the Properties window of the service through the Services management console.

Installing the service

This debuggable service can’t be installed yet, as running installutil.exe on the assembly will show the error “No public installers with the RunInstallerAttribute.Yes attribute could be found”.

It can also be useful to make the service self-installing, so you won’t have to rely on installutil.exe being present on the target machine. The following code enables a service to install itself, after adding a reference to the .NET assembly System.Configuration.Install:

Third-party

You don’t want to reinvent the wheel. Using above code, I showed why and how you would do this. There are various libraries that encapsulate this behavior so you don’t have to write and maintain it anymore. To name a few:

Each of these and other libraries have their own mindset. Some are config-oriented, some use properties and others rely on attributes you have to place in your code. There are libraries that come with a user interface to start and stop the service being debugged.
Most or all of these libraries are also available as NuGet packages.