Click here to Skip to main content
15,886,137 members
Articles / Web Development / ASP.NET
Article

Debugging Windows Services under Visual Studio .NET

Rate me:
Please Sign up or sign in to vote.
4.91/5 (116 votes)
14 Aug 2006CPOL1 min read 601.9K   181   89
How to 'fudge' Windows Services code so that it can be debugged under Visual Studio .NET.

Introduction

Normally, debugging a Windows service under Visual Studio .NET is painful. Windows services won't actually run directly within Visual Studio .NET, so the usual technique is to install and start the Windows service and then attach a debugger to it. An alternative approach is to pull the guts out of the service, stick it in a separate library, and then build some other app (e.g., a console app) to sit in front of it. This approach uses neither of those techniques.

When building a C# Windows Service project in Visual Studio, it will leave you with a class containing quite a few methods including a Main(), such as this:

C#
// The main entry point for the process
static void Main()
{
    System.ServiceProcess.ServiceBase[] ServicesToRun;

    // More than one user Service may run within the same process. To add
    // another service to this process, change the following line to
    // create a second service object. For example,
    //
    // ServicesToRun = new 
    //      System.ServiceProcess.ServiceBase[] {new Service1(), 
    //      new MySecondUserService()};
    //

    ServicesToRun = new System.ServiceProcess.ServiceBase[] { new Service1() };
    System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}

Obviously, it's the Main() above that ends up executing the service, and it's the Main() that this approach manipulates so that the Windows Service can be debugged directly within Visual Studio .NET.

Using the example above (and removing some of the comments), here's how:

C#
// The main entry point for the process
static void Main()
{
#if (!DEBUG)
    System.ServiceProcess.ServiceBase[] ServicesToRun;
    ServicesToRun = new System.ServiceProcess.ServiceBase[] { new Service1() };
    System.ServiceProcess.ServiceBase.Run(ServicesToRun);
#else
    // Debug code: this allows the process to run as a non-service.
    // It will kick off the service start point, but never kill it.
    // Shut down the debugger to exit
    Service1 service = new Service1();
    service.<Your Service's Primary Method Here>();
    // Put a breakpoint on the following line to always catch
    // your service when it has finished its work
    System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#endif 
}

It's crude, but effective (CBE - also known as Commander of the British Empire ;)). Run the service in debug mode to debug it, compile and install it as a release build, and it's a full and proper Windows service.

You may still wish to pull the guts out of your service into a separate library for unit testing. But this approach allows you to work with almost all of your service code as an actual service.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Founder md8n
Timor-Leste Timor-Leste
If it ain't broke - that can be arranged.

Comments and Discussions

 
GeneralRe: Very nice! Pin
dferreira04222-Aug-06 15:01
dferreira04222-Aug-06 15:01 
JokeRe: Very nice! Pin
Lee Humphries22-Aug-06 16:20
professionalLee Humphries22-Aug-06 16:20 
GeneralRe: Very nice! Pin
dferreira04222-Aug-06 16:40
dferreira04222-Aug-06 16:40 
JokeRe: Very nice! Pin
Lee Humphries22-Aug-06 16:49
professionalLee Humphries22-Aug-06 16:49 
GeneralClever workaround! Pin
moriority511-Aug-06 11:05
moriority511-Aug-06 11:05 
GeneralRe: Clever workaround! Pin
Lee Humphries13-Aug-06 11:21
professionalLee Humphries13-Aug-06 11:21 
GeneralSolution to that Pin
Leo Davidson15-Aug-06 2:18
Leo Davidson15-Aug-06 2:18 
GeneralThanks - And Some Extra Stuff Pin
jriesen27-Jun-06 20:31
jriesen27-Jun-06 20:31 
That was an elegant solution to the problem, even if it seems a little quick-and-dirty. What's funny is that I'm actually using this approach (with modifications) in a real-life production application at the moment. It got a little more complicated because I ended up wanting the ability to launch the service from other assemblies (e.g. from unit tests), but it works great for me... so I figured I'd share. Not like you necessarily want to use this code directly, but it shows how to mash the OnStart method, rather than calling a public method in the service. (I use it in this case because my service is so utterly short I'd rather not even bother with private methods.)

using System.Reflection;
using System.ServiceProcess;

public static class Program {
// Note that the real service has been renamed to MyService to protect the innocent. Smile | :)
private static MyService service = new MyService();

internal static void Main() {
#if (!DEBUG)
ServiceBase.Run( new ServiceBase[] { service } );
#else
Start();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#endif
}

public static void Start() {
InvokeServiceMethod("OnStart");
}

public static void Stop() {
InvokeServiceMethod("OnStop");
}

private static void InvokeServiceMethod(string methodName, params object[] parameters) {
if (parameters == null || parameters.Length < 1) {
parameters = new object[] { null };
}
service.GetType().InvokeMember(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, service, parameters);
}
}


Note the use of reflection to smash the OnStart method (or, really, any instance method you would like). Might be overkill, but I like reflection. Smile | :)

Also, you can probably scrap the compile-time test and replace it with one at runtime. I'm thinking about switching my code to do this (but be warned, it's not fully tested yet):

if (System.Diagnostics.Debugger.IsAttached) {
Start();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
}
else {
ServiceBase.Run(new ServiceBase[] { service });
}

Naturally, this assumes that you only want it to start this way while running in the Visual Studio (or other unmanaged) debugger. If you need to launch the service from the command line in the debugging mode, then it won't work. There -may- be some way to detect whether the app is being launched as a service (perhaps, say, through execution credentials - if you're running as LOCALSYSTEM it would be a good indicator), but I don't really need that functionality so I won't be pursuing it here.


Anyway, thanks for your help! Thought I'd try and give a little back too.
GeneralRe: Thanks - And Some Extra Stuff Pin
Lee Humphries28-Jun-06 12:26
professionalLee Humphries28-Jun-06 12:26 
GeneralBest article !!! Pin
Phan Dung7-May-06 22:59
Phan Dung7-May-06 22:59 
GeneralWorks great Pin
pchelp25-Apr-06 10:34
pchelp25-Apr-06 10:34 
GeneralThanks Pin
Victtim5-Apr-06 10:22
Victtim5-Apr-06 10:22 
QuestionHow about Pin
nfoyt30-Mar-06 13:18
nfoyt30-Mar-06 13:18 
AnswerRe: How about Pin
Lee Humphries30-Mar-06 13:33
professionalLee Humphries30-Mar-06 13:33 
GeneralAwesome!!! Pin
ajdiaz3-Mar-06 6:41
ajdiaz3-Mar-06 6:41 
Generalthanks - found this useful Pin
Jay Hamlin18-Nov-05 7:37
Jay Hamlin18-Nov-05 7:37 
GeneralCaveat ! Pin
tobia_p15-Sep-05 5:56
tobia_p15-Sep-05 5:56 
GeneralRe: Caveat ! Pin
Lee Humphries15-Sep-05 15:21
professionalLee Humphries15-Sep-05 15:21 
QuestionWhat is the gain? Pin
tgueth19-Apr-05 5:07
professionaltgueth19-Apr-05 5:07 
AnswerRe: What is the gain? Pin
Lee Humphries19-Apr-05 15:13
professionalLee Humphries19-Apr-05 15:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.