Debugging Windows Services is a Pain
If you are taking time out to read this post, you have probably experienced the pain of debugging windows services. When I first started writing windows services, I looked far and wide for a solution that would allow me to hit the ol' F5 button in Visual Studio and be able to run everything fine.
If you believe Microsoft's advice, it's not possible. The MSDN article on the subject suggests a six step process that will not allow you to debug the OnStart method of the service. If you read further, they suggest you add a dummy service to your code so that you can fire up the dummy service, attach your debugger, then start the real service. Not only is this a pain, but you are left with a bunch of dirty dummy code littering all of your projects. I don't know about you, but that doesn't sound like a good time.
Another easier method I've seen bandied about is using the System.Diagnostics.Debugger.Launch(); function in a #if DEBUG compiler directive. Paul Ballard has a good article on using this approach. This still requires you to interact with the windows services interface and start the service and attach the debugger to the service. It's made a little easier by popping up a debug dialog for you AND you can debug the OnStart method this way, but alas, it's not the ideal situation.
Something that gets a little closer to what I want (hit F5 and go) is an article on The Code Project called Debugging Windows Services under Visual Studio.NET. The article itself itsn't doesn't add much more to the solution than Paul's article, but a commenter, 'jreisen', posts a clever comment that utilizes reflection to make the debug code a little more generic to work with all services.
Now we are talking! I can work with this.
Solution
I took all of these suggestions and made them into something that can be run both in be debugged with a simple F5 in Visual Studio and deployed to a production windows services environment with no code changes.
Before I talk a little bit about how it works, here's how to use it.
Here is the typical code in the Main function (located in the Program.cs code file):
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new Service1() };
ServiceBase.Run(ServicesToRun);
And here is the same code modified to use my debugging code:
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new Service1() };
//ServiceBase.Run(ServicesToRun);
ServicesLoader.StartServices(ServicesToRun);
Just changing this one line will show this dialog at runtime when a debugger is attached:
If you try to run the application without a debugger attached, you get the all too familiar "Cannot start service from a command line or a debugger" message box (just like we want). If there is not a debugger attached the service will assume it is being run from the windows service API making it easy to test in that scenario as well.
Just use the user interface to call the OnStart, OnStop, OnPause, and OnContinue methods (using familiar controls like those in the Windows Services MMC snap-in) and debug at your leisure.
How's this work?
There's not too much magic here, really. The real meat of the StartServices method of ServicesLoader is in this section of code here:
if (System.Diagnostics.Debugger.IsAttached)
{
ShowInterface(ServicesToRun);
}
else
{
ServiceBase.Run(ServicesToRun);
}
Here we are just utilizing the System.Diagnostics.Debugger class to decide what section of code to execute. The ShowInterface method simply shows the dialog box you see above. The rest is just a little reflection to call the OnStart, OnStop, etc methods.
YOUR code in MY deployment?
If you don't like the idea of deploying production code with this assembly being called (I wouldn't be offended), you can modify your service code a bit further to be assured this function isn't being called in your Release builds:
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new Service1() };
#if (!DEBUG)
ServiceBase.Run(ServicesToRun);
#else
ServicesLoader.StartServices(ServicesToRun);
#endif
This way if your code breaks in production, you can be assured it has nothing to do with me.
Download
Hope this helps someone. Here is a full download:
Service Debugging Helper (Binary)
Service Debugging Helper (Binary + Source)
Bugs? Contact Me.
[Update: 12-28-2006. Nic already found a bug related to the Play button not working on occasion. Thanks Nic. It's fixed.]
[Update: 01-04-2007. Been using this myself for a couple of days straight. I Found some stuff I thought was annoying and added a few features. Now gives you better exception information as well as a handy "Auto Start" feature.]
[Update: 05-04-2007. Community Server downloads seem to have broken zip files on my site at the moment. I've updated the above links with better download links until I can get this resolved. The source and binary have also been updated with a few bug fixes submitted by Kevin Durdle of Shelfari, a very interesting new community site targetted toward book readers. Thanks Kevin!]
[Major Update: 08-22-2007. Added a Service Runner program that will execute .NET services without a debugger or modifying any code. Details here.]
Trackbacks
Comments
Francesco
:
Gagan
:
Ben
:
suman
:
Andy
:
Graham
:
Joe
:
daniel
:
Jason
:
Jon
:
dEUS
:
dEUS
:
dEUS
:
senorAli33
:
Pontus
: