Search
Close this search box.

C# Toolbox: A Debuggable, Self-Installing Windows Service Template (1 of 2)

Update: I have now placed the zip containing the source for the end result of part 1 and 2 of this service template here.

I decided to write a pair of posts on making it easier to create Windows Services in C# (and in .NET in general).  This is the first post that talks about how to make a Windows Service debuggable (the default visual studio template does not allow the service to be easily debugged), and then next week’s post will discuss making the Windows Service self-installing.

Now, these posts are not here to give you a comprehensive Windows Service framework, but just to describe how you can change the default Windows Service template to add these two easy features.  There’s a great Windows Service framework out there called the TopShelf Project which you can examine if you wish to see a more full-featured framework.

So why Windows Services?  Well, whenever you are creating a long-running executable application, that processes data, you may want to consider using a Windows Service.  Windows Services run in their own windows sessions and are not dependent on a user to be logged in.  Thus it’s harder for them to be interrupted than a console app by an unwary user. 

In addition, you have a lot of control of how Windows Services start up.  Not only can they start automatically when the server boots, but you can also remotely start and stop them as long as you have sufficient privileges.

Now obviously, Web Services have a lot of the same attributes (though they run under IIS instead), but Web Services tend to operate more on a request/response model whereas Windows Services tend to be more long-running processes. 

They aren’t always applicable for every problem you need to solve, but they can come in quite handy for processes such as listening to a SQL Server Service Broker Queue and processing the items therein.

The Problem With The Default Template

The main problem with Windows Services is the default Windows Service template in Visual Studio does not let you easily debug a Windows Service.  You could, of course, add a Thread.Sleep() to allow you to attach during early start-up, but this can be cumbersome.

For the Windows Services I develop at work, I’ve created a VS2010 template that can be used to make easily debuggable Windows Services. 

So what we are going to do is take advantage of a little known System.Environment property called UserInteractive.  When you query this property, it will tell you whether the application was started as an application with a user interface.

Typically, Windows Services return false for this property.  Whereas console and GUI applications return true.  Now, this isn’t necessarily dependent so much on the project type chose as how the application is started.  In our case, for a Windows Service if we attempt to start it through the Services console, UserInteractive will be false, but if we start from a command prompt, file explorer, IDE, etc it will return true.

This allows us to test this property and decide whether to start our Windows Service as a true service or whether to “stub” it as a console application.  The nice thing about this is if you use something like log4net or another capable logging framework, you can have both a file and console appender that will let you log application details to file, console, and event logs easily.

Building a Debuggable Service

So let’s create a debuggable Windows Service.  Start by creating a new Windows Service project in Visual Studio 2010.  I’ll call mine DebuggableService but feel free to call yours what you will, just remember that when I talk about DebuggableService to substitute your own project name. 

Notice you will get a very bare-bones solution that will look something like this:

Now, let’s verify what we’ve been talking about.  Let’s go to the class DebuggableService (or whatever you called your project) and add a Console.WriteLine() to the OnStart() method, and then place a breakpoint there:

Now, if you compile and run this, you will notice that the IDE gives you a lovely error to the effect that Windows Services cannot be run from the IDE:

Okay, so how do we work around this?  First of all, I’m going to create an interface called IWindowsService.  Why?  Well, I could just add a bunch of internal or even exposed methods in the ServiceBase implementation, but this feels very forced to me.  Instead I’m going to remove the behavior of the service from the fact that it is a ServiceBase since, as you’ll see, it now can act like a service but really be a console app instead.  So here’s the IWindowsService interface:

  1: using System;
   2:  
   3: namespace DebuggableService
   4: {
   5:     // The interface that any windows service should implement to be used
   6:     // with the GenericWindowsService executable.
   7:     public interface IWindowsService : IDisposable
   8:     {
   9:         // This method is called when the service gets a request to start.
  10:         void OnStart(string[] args);
  11:  
  12:         // This method is called when the service gets a request to stop.
  13:         void OnStop();
  14:  
  15:         // This method is called when a service gets a request to pause, 
  16:         // but not stop completely.
  17:         void OnPause();
  18:  
  19:         // This method is called when a service gets a request to resume 
  20:         void OnContinue();
  21:  
  22:         // This method is called when the machine the service is running on
  23:         void OnShutdown();
  24:     }
  25: }

Okay, now that we have this interface, we can modify the ServiceBase implementation (Service1 was its name in the generated project) to delegate calls to our IWindowsService.  Because this class will probably never change once we delegate, I’m going to rename it from Service1 to WindowsServiceHarness:

1: using System.ComponentModel;
   2: using System.ServiceProcess;
   3:  
   4: namespace DebuggableService
   5: {
   6:     // the new service base implementation
   7:     public partial class WindowsServiceHarness : ServiceBase
   8:     {
   9:         private IWindowsService _implementer;
  10:  
  11:         // default constructor to satisfy builder
  12:         internal WindowsServiceHarness()
  13:         {
  14:             InitializeComponent();
  15:         }
  16:  
  17:         // public constructor to take in the implementation to delegate to
  18:         public WindowsServiceHarness(IWindowsService implementation) : this()
  19:         {
  20:             _implementer = implementation;
  21:         }
  22:  
  23:         // because all of these available overrides are protected, we can't
  24:         // call them directly from our console harness, so instead we will
  25:         // just delegate to the IWindowsService interface which is public.
  26:         protected override void OnStart(string[] args)
  27:         {
  28:             _implementer.OnStart(args);
  29:         }
  30:  
  31:         protected override void OnStop()
  32:         {
  33:             _implementer.OnStop();
  34:         }
  35:  
  36:         protected override void OnPause()
  37:         {
  38:             _implementer.OnPause();
  39:         }
  40:  
  41:         protected override void OnContinue()
  42:         {
  43:             _implementer.OnContinue();
  44:         }
  45:  
  46:         protected override void OnShutdown()
  47:         {
  48:             _implementer.OnShutdown();
  49:         }
  50:     }
  51: }

Now that we’ve done that, we’ll create an empty implementation of IWindowsService called ServiceImplementation, which will give the interface an implementation with all empty method bodies.  These will be filled in later by the user of our template.

 1: namespace DebuggableService
   2: {
   3:     public class ServiceImplementation : IWindowsService
   4:     {
   5:         // This method is called when the service gets a request to start.
   6:         public void OnStart(string[] args)
   7:         {
   8:         }
   9:  
  10:         // This method is called when the service gets a request to stop.
  11:         public void OnStop()
  12:         {
  13:         }
  14:  
  15:         // This method is called when a service gets a request to pause, 
  16:         // but not stop completely.
  17:         public void OnPause()
  18:         {
  19:         }
  20:  
  21:         // This method is called when a service gets a request to resume 
  22:         public void OnContinue()
  23:         {
  24:         }
  25:  
  26:         // This method is called when the machine the service is running on
  27:         public void OnShutdown()
  28:         {
  29:         }
  30:  
  31:         // dispose any resources
  32:         public void Dispose()
  33:         {
  34:         }
  35:     }
  36: }

Then, we will create a new ConsoleHarness class that will allow us to control the windows service from the console instead of through the Services Administration tool:
  1: using System;
   2:  
   3: namespace DebuggableService
   4: {
   5:     public static class ConsoleHarness
   6:     {
   7:         // Run a service from the console given a service implementation
   8:         public static void Run(string[] args, IWindowsService service)
   9:         {
  10:             string serviceName = service.GetType().Name;
  11:             bool isRunning = true;
  12:  
  13:             // simulate starting the windows service
  14:             service.OnStart(args);
  15:  
  16:             // let it run as long as Q is not pressed
  17:             while (isRunning)
  18:             {
  19:                 WriteToConsole(ConsoleColor.Yellow, "Enter either [Q]uit, [P]ause, [R]esume : ");
  20:                 isRunning = HandleConsoleInput(service, Console.ReadLine());
  21:             }
  22:  
  23:             // stop and shutdown
  24:             service.OnStop();
  25:             service.OnShutdown();
  26:         }
  27:  
  28:  
  29:         // Private input handler for console commands.
  30:         private static bool HandleConsoleInput(IWindowsService service, string line)
  31:         {
  32:             bool canContinue = true;
  33:  
  34:             // check input
  35:             if (line != null)
  36:             {
  37:                 switch (line.ToUpper())
  38:                 {
  39:                     case "Q":
  40:                         canContinue = false;
  41:                         break;
  42:  
  43:                     case "P":
  44:                         service.OnPause();
  45:                         break;
  46:  
  47:                     case "R":
  48:                         service.OnContinue();
  49:                         break;
  50:  
  51:                     default:
  52:                         WriteToConsole(ConsoleColor.Red, "Did not understand that input, try again.");
  53:                         break;
  54:                 }
  55:             }
  56:  
  57:             return canContinue;
  58:         }
  59:  
  60:  
  61:         // Helper method to write a message to the console at the given foreground color.
  62:         private static void WriteToConsole(ConsoleColor foregroundColor, string format,
  63:             params object[] formatArguments)
  64:         {
  65:             ConsoleColor originalColor = Console.ForegroundColor;
  66:             Console.ForegroundColor = foregroundColor;
  67:  
  68:             Console.WriteLine(format, formatArguments);
  69:             Console.Out.Flush();
  70:  
  71:             Console.ForegroundColor = originalColor;
  72:         }
  73:     }
  74: }

Now that we’ve completed that, we can modify the Main() method so that it will query the Environment.UserInteractive property and either call the ServiceMain or the ServiceConsoleHarness depending on how the program was started.
  1: using System;
   2: using System.ServiceProcess;
   3:  
   4:  
   5: namespace DebuggableService
   6: {
   7:     static class Program
   8:     {
   9:         // The main entry point for the windows service application.
  10:         static void Main(string[] args)
  11:         {
  12:             using(var implementation = new ServiceImplementation())
  13:             {
  14:                 // if started from console, file explorer, etc, run as console app.
  15:                 if (Environment.UserInteractive)
  16:                 {
  17:                     ConsoleHarness.Run(args, implementation);
  18:                 }
  19:     
  20:                 // otherwise run as a windows service
  21:                 else
  22:                 {
  23:                     ServiceBase.Run(new WindowsServiceHarness(implementation));
  24:                 }
  25:                 }
  26:         }
  27:     }
  28: }

One last thing, select the project (DebuggableService in my example) in the service explorer, open the properties, and change the application type to Console Application.  This will enable the console to open if run in interactive mode.

Let’s give this new code a spin now!  Move the breakpoint to ServiceImplementation.OnStart() and run:

It works!  Now let’s look at how we can make this into a template so we don’t have to re-implement this code every time we want to create a new Windows Service.

Building the Template

So, now that we have the debuggable service, how do we make it a VS2010 template?  Well, you can build the VSIX file yourself which involves knowing the correct manifests and files and structure, etc, or there is a very handy VS2010 Microsoft Export Template extension here that you can install that will convert any project into a template.  Go ahead and install it now if you haven’t.

There’s just one thing we need to do for convenience.  Anywhere that the solution name would be substituted in the template, we need to use template parameters instead.  These are substitution parameters that are populated when you actually create a new project of a given template type.  You can find a comprehensive list of the template parameters here on MSDN

For our purposes, we’ll use $safeprojectname$.  We want to use safe project name because it will strip non-valid identifier characters (such as spaces) from the name. 

Really, in the original Windows Service template the only thing that varied by project name was the namespace, so we’ll take the same approach and replace all instances of namespace DebuggableService (or whatever you called your project) to namespace $safeprojectname$.

Unfortunately, this will not let your code compile anymore, so make sure your build was error free before taking this step.  Now that we’ve made the substitutions, select on the project in the Solution Explorer, and then go to File->Export Template… menu option.

This will create the actual template file and will allow you to import into your VS2010 under the C# projects.  You can then pass this VSIX template on to the other members of your team so they can install it as well!

When the Choose Template Type dialog comes up, choose Project Template, and make sure DebuggableService (or whatever you called your project originally) is selected in the combo box.

Hit [Next] and you can then enter a new template name, description, and images to help let it stand out in the templates list.  The Automatically import the template into Visual Studio will create the template and automatically put it in the list of C# project templates whenever you create a new project.

Okay, let’s hit [Finish] and do it! If all goes well you will see a file explorer window with your new VSIX file that you can ship to your co-workers, and it should have been already installed into Visual Studio itself for you.

Using the Template

So let’s fire it up, open a new instance of Visual Studio and create a new project.  Notice our new template is there!

Let’s enter a project name for a quick test!  If you enter a project name and select okay, you should see the project name as the namespace in your program files.  You can now create new Windows Services using this template and easily let them be debugged, run from console, or run as a service.

So give it a whirl!  Add some Console.WriteLine() statements to your ServiceImplementation class and debug it or run it as a Console application.  We’ll cover installation as a service next week!

Summary

Now we’ve learned how to make a windows service easily debuggable and how to create a VS2010 template and import it into Visual Studio.  This can help you create a basic template for debuggable Windows Services that can be used over and again.

Next week I’ll talk about how to add a basic Installer to the template so that we can make the services generated by the template self-installing as well!

Also, as soon as I can I intend to update this post and place the code for this template on github.  I’ll let you know as soon as that’s done.  Until then, you can replicate with the steps above or feel free to e-mail or write a comment, which I try to check daily.

Hope you enjoyed the post, and if you’d like to see a nice full-featured Windows Service framework, check out the Topshelf Project project on github.

Technorati Tags: C#CSharp.NETWindows ServiceServiceTemplateVisual Studio

Share This Post:

  • Facebook
  • Technorati
  • Twitter
  • Short Url: http://wblo.gs/avY
This article is part of the GWB Archives. Original Author: James Michael Hare

Related Posts