Run a Windows Service as a console app

When working on a Windows Service project you may want to run it as a Console App so you can see what’s going on.

If you try to run the service in Visual Studio you’ll get an error that says: “Cannot start service from the command line or a debugger. A Windows Service must first be installed… .”

You really only have two options:

  1. Install the Windows Service and look at the logs. This is tedious and slows down development.
  2. Conditionally run the program as a console app

In this article I’ll explain how to run it as a console app.

1 – Set the project output type to Console Application

Check which scenario below matches your situation.

Note: If you don’t change your output type to Console App you’ll get an exception “System.InvalidOperationException: ‘Cannot read keys when either application does not have a console or when console input has been redirected from a file. Try Console.Read.’

If you already have a Windows Service project

Simply change the Output type to Console Application.

Project Application tab, showing Output type = Console Application

If you are starting a new project from scratch

Create a Windows Service project. Then change the Output type to Console Application.

2 – Conditionally run as console or as a service based on a command line argument

Check for the “/CONSOLE” command line argument to determine if you need to run as a service or as a console app.

If you are running as a service, the framework will call TestService.OnStart(), and then you’ll call TestService.StartService(). If you’re running as a console app you’ll call TestService.StartService(). In both cases you’ll end up calling the StartService() method.

using System;
using System.Linq;
using System.ServiceProcess;

namespace WindowsServiceAsConsole
{
    static class Program
    {
        public static void Main(string[] args)
        {
            if (args.FirstOrDefault()?.ToUpper() == "/CONSOLE")
            {
                RunAsConsole();
            }
            else
            {
                RunAsService();
            }
        }
        private static void RunAsConsole()
        {
            TestService serv = new TestService();
            serv.StartService();

            Console.WriteLine("Running service as console. Press any key to stop.");
            Console.ReadKey();

            serv.Stop();
        }
        private static void RunAsService()
        {
            /* Warning: Don't load the object graph or 
             * initialize anything in here. 
             * 
             * Initialize everything in TestService.StartService() instead
             */
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            {
                new TestService()
            };
            ServiceBase.Run(ServicesToRun);
        }
    }
}

Code language: C# (cs)

3 – Add StartService() to the service class

The key here is to create a method that is called by both the service and console app. The framework will call OnStart() when starting as a service. It’s important that all you do is call StartService() in a new thread here.

Note: Avoid doing any initialization in OnStart(). Windows enforces a “startup time” for services, and your service will not finish starting up if it’s taking too long in OnStart().

using System;
using System.ServiceProcess;

namespace WindowsServiceAsConsole
{
    public partial class TestService : ServiceBase
    {
        public TestService()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            new System.Threading.Thread(StartService).Start();
        }

        protected override void OnStop()
        {
        }

        internal void StartService()
        {            
            /* 
                This is the true composition root for a service,
                so initialize everything in here
            */
            Console.WriteLine("Starting service");
        }
    }
}

Code language: C# (cs)

4 – Add the /CONSOLE command line argument in the build options

To automatically run as a console app every time you start the program from Visual Studio, you can add the /CONSOLE flag as a command line argument. You should only do this for the Debug build configuration.

Project Debug tab with Command line arguments = /CONSOLE

Make sure you’re not passing in /CONSOLE for the Release build configuration, otherwise when you deploy it’ll run as a console app in production.

Project Debug tab with Command line arguments empty for Release configuration

Note: You can still run this as console app in production manually. Just open a command line and execute your exe with the /CONSOLE command line argument, like this:

PowerShell command: ./WindowsServiceAsConsole /CONSOLE

Comments are closed.