I’m working on a Windows Service application at The Day Job, and while I’ve done the usual test-driven development approach, I still have a few things I’m testing and polishing that are integration-related (such as things behaving slightly differently when using SQL Server instead of a mock).  Deploying a service isn’t difficult thanks to installutil, but it is still an extra hoop that I didn’t want to jump through as I tweaked my service.  With .NET, services are mostly just regular Windows applications, the difference is in what happens inside of the Main method:

//For a service application...
static void Main(string[] args)
{
    ServiceBase.Run(new[] { new MyAwesomeService() });
}

...

//For a WinForms application
static void Main(string[] args)
{
    Application.Run(new MyWinForm());
}

//For a console application
static void Main(string[] args)
{
    Console.WriteLine("Hello, world!");
    
    //Do stuff;
    
    return;
}

In a service application, the service class is registered using ServiceBase.Run.  With a WinForms application, you would show your first form from Main.  With a Console application, you would do some stuff and return from Main when its time to quit. 

If you attempt to debug or otherwise start a service application directly, you will see the following message: “Cannot start service from the command line or a debugger…”  If you want to run the service, you have to install it, which again, isn’t hard, but it takes longer than just pressing F5 does.

The solution is simple: allow your application to run either as a service OR as a regular application.  I implemented this behavior by checking for the existence of a “—debug” argument.  If set, the service runs as a regular application.  When not set, it runs as a service.  To make it easy to debug in Visual Studio, I added the “—debug” flag as an argument under the project properties “Debug” tab, so now pressing F5 or clicking “Debug” runs my service project in application mode.

Here’s how I implemented it:

static class Program
{
    static void Main(string[] args)
    {
        if (args[0] == "--debug")
        {
            RunAsConsoleApplication();
        }
        else
        {
            RunAsService();
        }
    }

    private static void RunAsConsoleApplication()
    {
        MyAwesomeService service = new MyAwesomeService();

        service.Start();

        ManualResetEvent blocker = new ManualResetEvent(false);

        Console.CancelKeyPress += delegate
                                    {
                                        service.Stop();
                                        blocker.Set();
                                    };

        blocker.WaitOne();
    }

    private static void RunAsService()
    {
        ServiceBase.Run(new[] { new MyAwesomeService() });
    }
}

Note that I’m using a ManualResetEvent to block the thread until Ctrl+C is pressed.  If you run your service as a WinForms application, you will never see a console, so you can’t press Ctrl+C to kill the application.  Instead, you’ll have to use “Stop Debugging” to kill it.  If however you set your project to run as a console application, you can press Ctrl+C to stop your service and shutdown the application just as if you had pressed the Stop button in the Windows service manager.

One other thing to note: my service class exposes Start and Stop methods that encapsulate the logic of OnStart and OnStop (which are what’s run when you start/stop the service from the Windows service manager). 

The solution isn’t perfect, but it works.  Anyone know of any alternatives?