[c#] .NET console application as Windows service

I have console application and would like to run it as Windows service. VS2010 has project template which allow to attach console project and build Windows service. I would like to not add separated service project and if possible integrate service code into console application to keep console application as one project which could run as console application or as windows service if run for example from command line using switches.

Maybe someone could suggest class library or code snippet which could quickly and easily transform c# console application to service?

This question is related to c# .net-4.0 windows-services console-application

The answer is


Firstly I embed the console application solution into the windows service solution and reference it.

Then I make the console application Program class public

/// <summary>
/// Hybrid service/console application
/// </summary>
public class Program
{
}

I then create two functions within the console application

    /// <summary>
    /// Used to start as a service
    /// </summary>
    public void Start()
    {
        Main();
    }

    /// <summary>
    /// Used to stop the service
    /// </summary>
    public void Stop()
    {
       if (Application.MessageLoop)
            Application.Exit();   //windows app
        else
            Environment.Exit(1);  //console app
    }

Then within the windows service itself I instantiate the Program and call the Start and Stop functions added within the OnStart and OnStop. See below

class WinService : ServiceBase
{
    readonly Program _application = new Program();

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main()
    {
        ServiceBase[] servicesToRun = { new WinService() };
        Run(servicesToRun);
    }

    /// <summary>
    /// Set things in motion so your service can do its work.
    /// </summary>
    protected override void OnStart(string[] args)
    {
        Thread thread = new Thread(() => _application.Start());
        thread.Start();
    }

    /// <summary>
    /// Stop this service.
    /// </summary>
    protected override void OnStop()
    {
        Thread thread = new Thread(() => _application.Stop());
        thread.Start();
    }
}

This approach can also be used for a windows application / windows service hybrid


Maybe you should define what you need, as far as I know, you can't run your app as Console or Service with command line, at the same time. Remember that the service is installed and you have to start it in Services Manager, you can create a new application wich starts the service or starts a new process running your console app. But as you wrote

"keep console application as one project"

Once, I was in your position, turning a console application into a service. First you need the template, in case you are working with VS Express Edition. Here is a link where you can have your first steps: C# Windows Service, this was very helpful for me. Then using that template, add your code to the desired events of the service.

To improve you service, there's another thing you can do, but this is not quick and/or easily, is using appdomains, and creating dlls to load/unload. In one you can start a new process with the console app, and in another dll you can just put the functionality the service has to do.

Good luck.


I use a service class that follows the standard pattern prescribed by ServiceBase, and tack on helpers to easy F5 debugging. This keeps service data defined within the service, making them easy to find and their lifetimes easy to manage.

I normally create a Windows application with the structure below. I don't create a console application; that way I don't get a big black box popping in my face every time I run the app. I stay in in the debugger where all the action is. I use Debug.WriteLine so that the messages go to the output window, which docks nicely and stays visible after the app terminates.

I usually don't bother add debug code for stopping; I just use the debugger instead. If I do need to debug stopping, I make the project a console app, add a Stop forwarder method, and call it after a call to Console.ReadKey.

public class Service : ServiceBase
{
    protected override void OnStart(string[] args)
    {
        // Start logic here.
    }

    protected override void OnStop()
    {
        // Stop logic here.
    }

    static void Main(string[] args)
    {
        using (var service = new Service()) {
            if (Environment.UserInteractive) {
                service.Start();
                Thread.Sleep(Timeout.Infinite);
            } else
                Run(service);
        }
    }
    public void Start() => OnStart(null);
}

You can use

reg add HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run /v ServiceName /d "c:\path\to\service\file\exe"

And it will appear int the service list. I do not know, whether that works correctly though. A service usually has to listen to several events.

There are several service wrapper though, that can run any application as a real service. For Example Microsofts SrvAny from the Win2003 Resource Kit


Here is a newer way of how to turn a Console Application to a Windows Service as a Worker Service based on the latest .Net Core 3.1.

If you create a Worker Service from Visual Studio 2019 it will give you almost everything you need for creating a Windows Service out of the box, which is also what you need to change to the console application in order to convert it to a Windows Service.

Here are the changes you need to do:

Install the following NuGet packages

Install-Package Microsoft.Extensions.Hosting.WindowsServices -Version 3.1.0
Install-Package Microsoft.Extensions.Configuration.Abstractions -Version 3.1.0

Change Program.cs to have an implementation like below:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace ConsoleApp
{
    class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).UseWindowsService().Build().Run();
        }

        private static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker>();
                });
    }
}

and add Worker.cs where you will put the code which will be run by the service operations:

using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp
{
    public class Worker : BackgroundService
    {
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            //do some operation
        }

        public override Task StartAsync(CancellationToken cancellationToken)
        {
            return base.StartAsync(cancellationToken);
        }

        public override Task StopAsync(CancellationToken cancellationToken)
        {
            return base.StopAsync(cancellationToken);
        }
    }
}

When everything is ready, and the application has built successfully, you can use sc.exe to install your console application exe as a Windows Service with the following command:

sc.exe create DemoService binpath= "path/to/your/file.exe"

I hear your point at wanting one assembly to stop repeated code but, It would be simplest and reduce code repetition and make it easier to reuse your code in other ways in future if...... you to break it into 3 assemblies.

  1. One library assembly that does all the work. Then have two very very slim/simple projects:
  2. one which is the commandline
  3. one which is the windows service.

I've had great success with TopShelf.

TopShelf is a Nuget package designed to make it easy to create .NET Windows apps that can run as console apps or as Windows Services. You can quickly hook up events such as your service Start and Stop events, configure using code e.g. to set the account it runs as, configure dependencies on other services, and configure how it recovers from errors.

From the Package Manager Console (Nuget):

Install-Package Topshelf

Refer to the code samples to get started.

Example:

HostFactory.Run(x =>                                 
{
    x.Service<TownCrier>(s =>                        
    {
       s.ConstructUsing(name=> new TownCrier());     
       s.WhenStarted(tc => tc.Start());              
       s.WhenStopped(tc => tc.Stop());               
    });
    x.RunAsLocalSystem();                            

    x.SetDescription("Sample Topshelf Host");        
    x.SetDisplayName("Stuff");                       
    x.SetServiceName("stuff");                       
}); 

TopShelf also takes care of service installation, which can save a lot of time and removes boilerplate code from your solution. To install your .exe as a service you just execute the following from the command prompt:

myservice.exe install -servicename "MyService" -displayname "My Service" -description "This is my service."

You don't need to hook up a ServiceInstaller and all that - TopShelf does it all for you.


So here's the complete walkthrough:

  1. Create new Console Application project (e.g. MyService)
  2. Add two library references: System.ServiceProcess and System.Configuration.Install
  3. Add the three files printed below
  4. Build the project and run "InstallUtil.exe c:\path\to\MyService.exe"
  5. Now you should see MyService on the service list (run services.msc)

*InstallUtil.exe can be usually found here: C:\windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.ex??e

Program.cs

using System;
using System.IO;
using System.ServiceProcess;

namespace MyService
{
    class Program
    {
        public const string ServiceName = "MyService";

        static void Main(string[] args)
        {
            if (Environment.UserInteractive)
            {
                // running as console app
                Start(args);

                Console.WriteLine("Press any key to stop...");
                Console.ReadKey(true);

                Stop();
            }
            else
            {
                // running as service
                using (var service = new Service())
                {
                    ServiceBase.Run(service);
                }
            }
        }

        public static void Start(string[] args)
        {
            File.AppendAllText(@"c:\temp\MyService.txt", String.Format("{0} started{1}", DateTime.Now, Environment.NewLine));
        }

        public static void Stop()
        {
            File.AppendAllText(@"c:\temp\MyService.txt", String.Format("{0} stopped{1}", DateTime.Now, Environment.NewLine));
        }
    }
}

MyService.cs

using System.ServiceProcess;

namespace MyService
{
    class Service : ServiceBase
    {
        public Service()
        {
            ServiceName = Program.ServiceName;
        }

        protected override void OnStart(string[] args)
        {
            Program.Start(args);
        }

        protected override void OnStop()
        {
            Program.Stop();
        }
    }
}

MyServiceInstaller.cs

using System.ComponentModel;
using System.Configuration.Install;
using System.ServiceProcess;

namespace MyService
{
    [RunInstaller(true)]
    public class MyServiceInstaller : Installer
    {
        public MyServiceInstaller()
        {
            var spi = new ServiceProcessInstaller();
            var si = new ServiceInstaller();

            spi.Account = ServiceAccount.LocalSystem;
            spi.Username = null;
            spi.Password = null;

            si.DisplayName = Program.ServiceName;
            si.ServiceName = Program.ServiceName;
            si.StartType = ServiceStartMode.Automatic;

            Installers.Add(spi);
            Installers.Add(si);
        }
    }
}

You need to seperate the functionality into a class or classes and launch that via one of two stubs. The console stub or service stub.

As its plain to see, when running windows, the myriad services that make up the infrastructure do not (and can't directly) present console windows to the user. The service needs to communicate with the user in a non graphical way: via the SCM; in the event log, to some log file etc. The service will also need to communicate with windows via the SCM, otherwise it will get shutdown.

It would obviously be acceptable to have some console app that can communicate with the service but the service needs to run independently without a requirement for GUI interaction.

The Console stub can very useful for debugging service behaviour but should not be used in a "productionized" environment which, after all, is the purpose of creating a service.

I haven't read it fully but this article seems to pint in the right direction.


Examples related to c#

How can I convert this one line of ActionScript to C#? Microsoft Advertising SDK doesn't deliverer ads How to use a global array in C#? How to correctly write async method? C# - insert values from file into two arrays Uploading into folder in FTP? Are these methods thread safe? dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Best way to "push" into C# array

Examples related to .net-4.0

TLS 1.2 in .NET Framework 4.0 Is it possible to run a .NET 4.5 app on XP? What and When to use Tuple? Fixing slow initial load for IIS Exception: "URI formats are not supported" What is the best way to implement a "timer"? Twitter Bootstrap and ASP.NET GridView How can I convert this foreach code to Parallel.ForEach? "This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded" Differences between .NET 4.0 and .NET 4.5 in High level in .NET

Examples related to windows-services

Can't start Tomcat as Windows Service Error 1053 the service did not respond to the start or control request in a timely fashion How to solve "The specified service has been marked for deletion" error Service will not start: error 1067: the process terminated unexpectedly How to get all Windows service names starting with a common word? Windows service with timer Windows service on Local Computer started and then stopped error Windows service start failure: Cannot start service from the command line or debugger "Automatic" vs "Automatic (Delayed start)" How to install node.js as windows service?

Examples related to console-application

How to run .NET Core console app from the command line ASP.NET Core configuration for .NET Core console application How to keep console window open How to navigate a few folders up? How to stop C# console applications from closing automatically? Could not load file or assembly ... An attempt was made to load a program with an incorrect format (System.BadImageFormatException) Can I write into the console in a unit test? If yes, why doesn't the console window open? What is the command to exit a Console application in C#? Can't specify the 'async' modifier on the 'Main' method of a console app Why is the console window closing immediately once displayed my output?