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

Temporary Blog Name :

Debugging Windows Services is a Pain - Anderson On... Link

Anderson On... :

I've had a lot of people say that the Service Loader I created is great, but that they would like the

Link

Ryan Ternier :

I posted an article about Sites, References and Articls that I cannot work without awhile back. I decided

Link

Anders Cui :

本期链接列表的主要内容有:ASP.NET MVC Framework, MVP, 设计模式, Python, 英语学习 :)

Link

TrackBack :

Comments

Nic :

Yay!  No more Start, then racing to the debugger to attach, and hoping it doesn't crash Visual Studio.

Link

Anderson Imes :

I forgot about it actually crashing VS quite a bit.  Another good reason!

Link

Francesco :

great!

Link

Darren :

That's cool!  Thanks dude!

Link

Anderson Imes :

Not a problem!  Let me know if you have any suggestions or questions.

Link

cykophysh :

Been using your solution , and it's really cool, would just like to say thanks

Link

Anderson Imes :

Not a problem.  Thanks for the thanks.

Link

Gagan :

Thanks a lot!!!!

You save my lot of time....:)

Link

Ben :

Thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you thank you !!!!!111  

really don't know what i'd do without this

Link

suman :

Andy,

You have saved me a lot of time and work.

I would like to Thank you very much.

Link

Anderson Imes :

Glad I could help.

Link

Andy :

Excellent. I'm using this right now. I only wish I'd found your solution to service debugging sooner! Thank you so much for saving my sanity on my current project ;)

Link

Graham :

Much obliged! Thankfully I found this article as I was writing my first service

Link

Joe :

Very cool -- thanks! :O)

Link

John Howard :

Hi Anderson,

I just wanted to say many thanks for the component, it has saved me many headaches and makes service development painless.

Great work!

Link

daniel :

Thanks....., very good work

Link

Jason :

Wow.  Thanks!

Link

Anderson Imes :

Thanks for everyone's nice comments.

Link

Jon :

Thanks a lot for sharing this, it makes debugging services a heck of a lot easier.

It's a shame you had to do work MS should have done... I wonder if they'll give us something in Orcas.

Link

Einar Egilsson :

I was recently trying to figure out a way to do something similar. Only difference is I wanted to be able to run my program both as a Windows Service or as a standalone console program, without any special builds, #DEBUG directives or command line parameters. I came up with another solution thats described at: http://tech.einaregilsson.com/2007/08/15/run-windows-service-as-a-console-program/ Link

Anderson Imes :

Well, you don't have to modify anything except that one line of code in the Main function to get this to work....

But, your point is noted.  I've received other feedback to the point that people would like to use this to execute the service without visual studio or the services admin tool.  I might create something that would allow that.

Link

Einar Egilsson :

Yeah, after reading the article again I figure we're kinda aiming for two different things. Your version is better suited for debugging in VS, while the main point of mine is to be able to run the program either as either a standalone application or a windows service.

Link

dEUS :

Hi,

Thanks a lot!!!! The tool is very helpful!!!

I am having a little trouble to use your tool in .NET framework 3.

In my service I use the new System.Configuration package.

When I start my service with your tool I get this exception:

{"An error occurred creating the configuration section handler for playbackSettings: 'MaxValueString' property specified was not found."}

Apparently you use the old configuration package.

Do you know what should I do to fix this problem? (I can remove the new configuration attributes…).

How exactly you load the service configuration file?

Link

dEUS :

Oh, i forgot one minor thing, sorry...

My service uses WCF with Multiple Concurrency Mode (the WCF messages come to the service thru mutilpe threads).

When I run my service with this tool the entire messages reached the service true a single thread.

I didn’t look on the tool code. Do you know what could be the reason for this?

Thanks!!

Link

Anderson Imes :

I'll have to take a look at this problem - I haven't tried this with an updated version of System.Configuration yet.  I'll post an update when I can.

Link

Anderson Imes :

dEUS:  Can you confirm that the application works as desired when installed as a regular service, but does not work when using the Services Controller?  If so, can you email me a short sample of what you are trying to achieve?  I have used this tool with a lot of WCF services with Single, Reentrant, and Multiple concurrency modes and haven't seen it "force" single concurrency mode (this is my understanding of your issue - let me know if I misunderstand).

Thanks!

Link

dEUS :

You understand the problem perfectly!

I am almost sure that the tool “force” single concurrency mode.

When the service starts as a regular service I get the operations on multiple threads as require.

You just need to delay the service operation a little bit and call the operation from multiple threads/clients:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]

public class MyService : IService

{

public void function1()

     {

Thread.Sleep(5000);

Console.WriteLine(Thread.CurrentThread.ManagedThreadId);

     }

}

Thanks for the quick reply!!!

Link

Anderson Imes :

dEUS:

I'm unable to replicate the issue you described.  I'm getting the following output:

14
15
3
14
3
16
17
....

As expected.  If you would like to discuss this further, please email me using the Contact link above.

Link

Anderson Imes :

Also, I've not been able to replicate the issue you've described regarding System.Configuration.  I even updated to .NET 3.5, which is the only .NET version that appears to make any updates to core DLLs.  Again, if you want to persue this, use the contact link above.

Link

senorAli33 :

Hi Anderson. I have a service with multi threads and I want to debug a specified thread but not have to wait other threads. Can you give me any solution. Thanks.

giaptd@gmail.com

Link

Anderson Imes :

Debugging threads is a little tricky, but it is possible.  There are two tools you should know about when dealing with threads.

The first is the "Threads" debugging window in Visual Studio 2005.  Debug -> Windows -> Threads.  This shows you all of the currently running threads.  When a breakpoint is hit, you can double-click on any thread to switch to it to see where it is currently executing, plus local variables, etc.

The second thing that you can use are breakpoint filters.  Visual Studio has a sophisticated set of tools for making breakpoints hit only in certain conditions.  Right-Click on any breakpoint you have created and click on "Filter...".  This will allow you to specify a value for these values: ProcessId, MachineName, ProcessName, ThreadId, and ThreadName.  This should ensure at least that your breakpoints are hit only when the desired thread is on the stack.  

Stepping through the code will allow other threads to be popped onto the stack so you might get some strangeness there.  If you do decide to step through the code at this point, keep an eye on the "Threads" window I mentioned above to make sure you are still on the same thread as you are going through.

Good Luck.

Link

Pontus :

Thanks, this was really helpful!

Nice little app =)

Link

Tom Leoanrd :

Very nice, very helpful, very ellegant. Thanks !!

Link

Amit Ranjan :

Hi,

This code is excellent, but after implementing this in one of my windows service I am not able to stop the service from windows service control. My service doesn't runs in release mode, onstart() method is never called.

Link

Anderson Imes :

Can you send me a sample of what you have implemented?  I've not yet heard this complaint.  If I understand, you have 2 issues:

1.  Cannot stop the service if it was compiled in debug.

2.  Cannot start the service if it was compiled in release mode.

Is that right?

Link

Anderson Imes :

I forgot to post a while back, but I worked with Amit offline and we were able to resolve his issue.  It turned out to be a rogue timer doing things that were unexpected.

Link

Steven A. Lowe :

An excellent tool, thank you. This greatly simplified tracking down some last-minute problems with two windows services, after all else had failed.

Link

Leave a Comment