ReBuildAll Blog
Thoughts (mostly) on .NET development

Easy debugging of Windows Services   (Framework)   
Ever wanted to create a Windows Service, but found it is very hard to debug? Here are two tips to make debugging easy.

Use the Debugger class to break into the service when starting

Have you read my previous post about the Debugger.Break() statement? You can read it here: Debugger breakpoints from code. The same method can be used with Windows Services to break into the code as it is being executed. If you want to break into the code just as your service is starting up, add the following code to the class constructor:

    public partial class MyService : ServiceBase
    {
        public MyService ()
        {
            this.ServiceName = "MyService";
            
            Debugger.Break();

            InitializeComponent();
        }
    ...


This will popup an application error message just as the execution is over the line - just as your service is starting up. You just need to say you want to debug it, and attach a debugger to it. If you have your service code open in Visual Studio, you can just use your existing instance of Visual Studio to debug the service. You can then monitor the startup, or add additional breakpoints.

You are not limited to breaking in the constructor - just add the statement wherever you need it.

As the debugger attached, Visual Studio will tell you there is no source code to display. But don't panic, just hit the step over (F10) debug command and you will end up at the statement after the Break() call.

Make your service a normal application for debugging

Another way to solve this problem is to turn your service into a normal Windows or Console application, that you can debug the traditional way. I like this approach, because I can run my application normally, without the hassle of the Service interface, until I am ready to run it as a service. This method makes it possible to seamlessly transition from "normal" run into "service" run, back and forth, as needed.

To make this happen you will have to alter your startup and stop code of the service. You need to do this, because the startup and stop code needs to be accessible from the outside, and ServiceBase have them defined as protected.

If you are worried about this solution, you can always put #if DEBUG precompiler statements around the code you enter. This way it will only be available in the debug version and you do not need to worry about it in the release version (if this is an issue at all).

An easy way to get started is to modify it like the following example. We add two new methods to the class:

    public partial class MyService : ServiceBase
    {
        public MyService ()
        {
            this.ServiceName = "MyService";
            InitializeComponent();
        }

        protected override void OnStart ( string[] args )
        {
            HandleStart();
        }

        protected override void OnStop ()
        {
            HandleStop();
        }

        public void HandleStart ()
        {
            // real startup logic
        }

        public void HandleStop ()
        {
            // real stop logic
        }
    }


When the application is invoked as a service, HandleStart() and HandleStop() methods will be called to handle the actual startup and teardown logic. But now you can also call these methods from your alternate solution.

If you want even more abstraction, you can just create two separate classes. One will contain the actual logic you need to perform, but will be a regular class derived from object. This would contain the HandleStart() and HandleStop() methods I described above. The actual ServiceBase derived class will be a wrapper (think Adapter pattern) around this regular class.

Now after this little modification is complete you still need to alter the startup code.

The default Visual Studio Service project template will generate a Windows application, so you can't really use the console. But no worries, add a reference to System.Windows.Forms, and then change the startup code. Look at the following example. (This reference might be a bad idea in some cases, but I will not go into the cons of this solution, at least not in this post).

        static void Main ( string[] args )
        {
            if ( args.Length > 0 &&
                 args[0] == "console" )
            {
                var service = new MyService();
                service.HandleStart();

                MessageBox.Show( "Press OK to quit" );

                service.HandleStop();
            }
            else
            {
                ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[] 
			    { 
				    new MyService() 
			    };
                ServiceBase.Run(ServicesToRun);
            }
        }


What this code does is when it detects the command like argument "console" it will not invoke the service startup code, instead it will proceed to instantiate the service class and invoke the methods we added above. If you wanted to go with the abstraction case, you would forget about the ServiceBase derived class here, and simply use your custom class directly.

The code displays a simple MessageBox, and the service will close when the user presses the "OK" button.

Whichever way you go, debugging services can be made really simple, which is a big plus when you need to debug them often.

 

Comments

There are no comments for this blog entry.