System.Diagnostics.Debugger

I hardly ever use the classes in the System.Diagnostics namespace.  As much as I’d like everyone to believe that it’s because I’m such a rockstar that I don’t need them, it’s really just that I generally use other techniques.  With Visual Studio providing so many tools for debugging I’ve rarely had reason to dig into this namespace much.  Sure, I’ve used the Debug, Trace, and EventLog classes but I haven’t taken the time to investigate what else is in there.

Early last week a coworker and I were discussing ways to debug some Windows Services.  If you’ve ever tried to debug a Windows Service’s startup sequence you know how painful it can be.  Our services have always followed the familiar pattern of:

public static void Main()
{
	var service = new MyService();
	System.ServiceProcess.ServiceBase.Run(service);
}

Of course, trying to run this code outside the context of a Windows Service results in the following error message:

Cannot start service from the command line or a debugger. A Windows Service must first be installed (using installutil.exe) and then started with the ServerExplorer, Windows Services Administrative tool or the NET START command.

So how can we debug the startup sequence if it throws that error?

The way I’ve handled this in the past is to add a Start method to the service class and revise the Main method with a conditional directive.

public static void Main()
{
	var service = new MyService();

#if !DEBUG
	System.ServiceProcess.ServiceBase.Run(service);
#else
	service.Start();
#endif
}

It’s clearly not an ideal solution but it lets me set a breakpoint anywhere within startup processing and run the service through Visual Studio.  My coworker (Thanks, Mike!) offered up an alternative solution that I’ll be using from now on.

Rather than messing with symbols and directives he suggested using the Debugger class in System.Diagnostics.  In particular he referred to two methods:

  • Launch()
  • Break()

It turns out that both are quite handy.  Launch() is used to programmatically launch and attach a debugger.  When Launch() is called we’re presented with the “Do you want to use the selected debugger?” dialog.  Break() is used to signal a breakpoint just like if we’d set one in the IDE and will prompt us to attach a debugger if we haven’t done so already.  With this technique we don’t need to mess around with the Main method and can instead modify our service class’ OnStart method to include a call to one or both of those methods instead.

protected override void OnStart(string[] args)
{
	System.Diagnostics.Debugger.Launch();
	base.OnStart(args);
}

Debugger isn’t limited to those two methods either.  It also provides a few other methods and properties for logging, detecting whether a debugger is attached, and notifying the debugger when the code is about to enter an area with cross-thread dependencies (like remoting).

A day without learning is a day wasted.
— Unknown

Hopefully I won’t have to resort to this very often but I’m happy to have it as another option.  Now I’m wondering which other namespaces I should take a closer look at.

Advertisements