.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?


I usually use the following techinque to run the same app as a console application or as a service:

public static class Program
{
    #region Nested classes to support running as service
    public const string ServiceName = "MyService";

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

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

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

    static void Main(string[] args)
    {
        if (!Environment.UserInteractive)
            // running as service
            using (var service = new Service())
                ServiceBase.Run(service);
        else
        {
            // running as console app
            Start(args);

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

            Stop();
        }
    }

    private static void Start(string[] args)
    {
        // onstart code here
    }

    private static void Stop()
    {
        // onstop code here
    }
}

Environment.UserInteractive is normally true for console app and false for a service. Techically, it is possible to run a service in user-interactive mode, so you could check a command-line switch instead.


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 eg 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:

  • Create new Console Application project (eg MyService)
  • Add two library references: System.ServiceProcess and System.Configuration.Install
  • Add the three files printed below
  • Build the project and run "InstallUtil.exe c:pathtoMyService.exe"
  • Now you should see MyService on the service list (run services.msc)
  • *InstallUtil.exe can be usually found here: C:windowsMicrosoft.NETFrameworkv4.0.30319InstallUtil.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:tempMyService.txt", String.Format("{0} started{1}", DateTime.Now, Environment.NewLine));
            }
    
            public static void Stop()
            {
                File.AppendAllText(@"c:tempMyService.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);
            }
        }
    }
    
    链接地址: http://www.djcxy.com/p/51160.html

    上一篇: 确保Linux中的应用程序的单个实例

    下一篇: .NET控制台应用程序作为Windows服务