Debug Windows Service in Visual Studio

In a lot of projects I use Windows Services to host services in Client-Server scenarios. In order to debug the service Microsoft recommends to install the service, start it and attach the Visual Studio debugger to the process.

Doing it this way you have to be aware of these things:

  • The service must be installed on your machine using installutil
  • You must stop the service each time you build your project because otherwise the .exe is locked
  • Don´t forget to uninstall the service before you change the namespace of the project or if you move/delete it. Otherwise the service instance remains installed and you have to remove the appropriate registry keys manually
  • Too many clicks for such a simple thing 🙂

You can also use frameworks like Topshelf to ease your development. But often the customer isn´t interested in getting a product that contains frameworks others than Microsoft´s and sometimes, as a developer, you don´t see the need of a separate framework.

Hence I used a simple but effective way at Tekaris to solve that problem, demonstrated by the following example project:

  1. Set the type of the project that contains the Windows service to “Console Application”
    consoleapp
  2. Add a public method Start to your service and move the logic of your OnStart method to it
  3. Call the Start method in the OnStart method
    public class MyWindowsService : ServiceBase
    {
        public void Start()
        {
            // Do your work here
         }
    
         protected override void OnStart(string[] args)
         {
             Start();
         }
    
         protected override void OnStop()
         {
             // Do you cleanup here
         }
     }
    
  4. Create and start the service in the Main method of the Program.cs of the Windows service project
    private static void Main(string[] args)
    {
        var service = new MyWindowsService();
    
        if (Environment.UserInteractive)
        {
            Console.WriteLine("Starting {0}...", service.GetType().Name);
            service.Start();
            Console.WriteLine("{0} is running...", service.GetType().Name);
            Console.WriteLine("Enter C to stop the service.");
    
            var input = Console.ReadLine();
            while (input != "C")
                input = Console.ReadLine();
        }
        else
            ServiceBase.Run(new ServiceBase[] {service});
    }
    

The “trick” is to check whether the application runs in an user interactive environment. That´s the case if you start your solution in Visual Studio. The public Start method is necessary because the protected OnStart method of the service is called by the framework.

if (Environment.UserInteractive)
{
    ...
}

When you install the service via the installutil command and start it via the “Local Services” snapin, the environment is not user interactive and the default behavior for starting a Windows service takes place.

ServiceBase.Run(new ServiceBase[] {service});
Advertisements