Five ways debugging .NET Windows service

Although debugging a Windows service is not so easy, especially you want to step into OnStart codes, there still exist a couple of techniques to get it done. I compiled them here in order to let Internet searchers get their work done as easy as possible.

1. Sleeping reasonable time to let you attach the service process into Visual Studio.

Writing the first line of OnStart as “System.Threading.Thread.Sleep(25000);”, you’ll be able to have enough time to attach service process into Visual Studio. It’s a little annoying if you’re fast hand, because you have to wait some seconds before hitting your breakpoints. Life is short. (see ref.)

2. Using conditional directive to determine running in service or normal console mode.

By applying #if(!DEBUG)…(1)…#else…(2)…#endif on your Main method, you’ll be able to write service codes into (1) and the testing codes into (2). What does testing codes look like? Please see the following snippets. You can set breakpoints whichever line you want. (see ref.) Michael also mentioned checking "Environment.UserInteractive" to distinguish it's running under service mode. (for details, see comments below from Michael)

Service1 service = new Service1();

service.OnStart(null);

Console.ReadLine();

service.OnStop();

3. Breaking at service process runtime. (Thanks Paul Ballard's comment)

In debug mode, you can insert “System.Diagnostics.Debugger.Lauch() ;” before the codes where you'd like to be prompted debugger window. So once you start the service from SCM (Service Control Manager), the codes has chance being hit. It actually reminds me that Windows API -- "DebugBreak" or even lower level -- INT 3, both of them might do the same thing in unmanaged world. (see ref.)

4. Using self-built switcher to specify running in service or normal console mode.

Moving forward, if we add switcher in the program, which might be even convenient. For example, if we run “Service1.exe console”, it will silently run as console app, otherwise it just go ahead as service. The detail implementation is quite similar to the codes of #2. The only difference is that whether to run testing codes is based on the Main method's parameters instead of using conditional directive. The benefit of the approach is even in release mode, we are able to monitor the service status if we enable kind of tracking mechanism.

5. Building separate assembly.

Regardless any service or console context, we can simply build an assembly implementing kind of interfaces like Start, Stop, etc. We can test these methods by using unit test or any other test scenarios you want. Once it’s done, it’s basically OK for you to embed the assembly into a service project template created by Visual Studio. (for details, see comments below form Jack)

The only drawback of #2, 4 and 5 is that using normal console mode, the account of service might not be able to get tested, because it’s probably not launched as the account's privilege supposed to be, such as localsystem, networkservice, etc. For the account privilege tests, the #1 and 3 are still valid.

Happy compiling…