Running a Windows Service inside a Console Application

I pretty much always use the same snippet of code when working with a Windows Service.  The main problem with a Windows Service is that it actually needs to be installed before you can run it.  While this works fine when deploying an application, we need to be able to debug and run the service without installing it during development.

Running the Service as a Service

Let’s assume we have a console application with a Windows Service named ‘Service’.  The code to run this service when our application is installed is pretty simple.

static void Main(string[] args)
{
    AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

    var service = new Service();

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

    AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException;
}

We can only use this if our application is installed as a service.  If you try and run this code from Visual Studio you will get the following error:

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.

Running the Service as a Console Application

We first need to modify the ‘Service’ class to be able to call the OnStart and OnStop methods, which are protected by default.

public void ManualStart(string[] args)
{
    OnStart(args);
}

public void ManualStop()
{
    OnStop();
}

Now we simply need to modify our Main method to start the service and then wait for input from the user.  I’m going to use compiler directives here – I want the application to start as a console application in Debug mode and starts as a Windows Service in Release mode.  This means I need to deploy my application in Release mode, but you should probably be doing that in any case.

static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

            var service = new Service();
#if DEBUG
            service.ManualStart(args);

            Console.WriteLine("Service started, press any key to kill");
            Console.ReadKey();

            service.ManualStop();
#else
            ServiceBase.Run(new ServiceBase[] { service });
#endif

            AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException;
        }

Now our application will start as a console application in Debug mode and as a Windows Service in Release mode.

Only kill the service on Ctrl-C

I used this code quite often and quickly realized that stopping the service when you press a key is rather annoying – you tend to do it by accident a couple of times each day.  To get around this I simply changed the code to only stop the service when you press Ctrl-C.

Console.WriteLine("Service started, press Ctrl-C to kill");
Console.TreatControlCAsInput = true;
while (true)
{
    var keyInfo = Console.ReadKey(true);
    if (keyInfo.Key == ConsoleKey.C && keyInfo.Modifiers == ConsoleModifiers.Control)
    {
        break;
    }
}

Happy coding.