.NET控制台应用程序作为Windows服务

Tom*_*mas 137 c# windows-services .net-4.0 console-application

我有控制台应用程序,并希望将其作为Windows服务运行.VS2010具有项目模板,允许附加控制台项目和构建Windows服务.我想不添加单独的服务项目,如果可能的话,将服务代码集成到控制台应用程序中,以将控制台应用程序保存为一个项目,该项目可以作为控制台应用程序运行,也可以作为Windows服

也许有人可以建议类库或代码片段,它可以快速,轻松地将c#控制台应用程序转换为服务?

Vla*_*adV 176

我通常使用以下技术来运行与控制台应用程序或服务相同的应用程序:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

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.

  • 您使用ServiceInstaller类,请参阅http://msdn.microsoft.com/en-us/library/system.serviceprocess.serviceinstaller.aspx. (3认同)
  • 只需在项目中添加对** System.ServiceProcess **的引用,您就可以使用上面的代码 (3认同)
  • 可以预期-您的服务将作为一个单独的进程运行(因此将显示在任务管理器中),但是该进程将由系统控制(例如,根据服务设置启动,停止,重新启动)。 (2认同)
  • 如果将其作为控制台应用程序运行,则不会看到服务。此代码的全部目的是使您可以将其作为控制台应用程序或服务运行。要作为服务运行,您需要先安装它(使用ServiceInstaller类-参见上面的MSDN链接-或installuitil.exe),然后从控制面板运行该服务。 (2认同)
  • ServiceInstaller只是用于处理Windows服务的实用程序类(有点类似于installutil.exe或sc.exe实用程序)。您可以使用它来安装任何您想作为服务的东西,操作系统并不关心您使用的项目类型。 (2认同)

sai*_*lle 54

我在TopShelf上取得了巨大的成功.

TopShelf是一个Nuget包,旨在使创建可以作为控制台应用程序或Windows服务运行的.NET Windows应用程序变得容易.您可以快速连接事件,例如服务启动和停止事件,使用代码配置,例如设置运行的帐户,配置对其他服务的依赖关系,以及配置从错误中恢复的方式.

从包管理器控制台(Nuget):

安装包Topshelf

请参阅代码示例以开始使用.

例:

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");                       
}); 
Run Code Online (Sandbox Code Playgroud)

TopShelf还负责服务安装,这可以节省大量时间并从您的解决方案中删除样板代码.要将.exe作为服务安装,只需在命令提示符下执行以下命令:

myservice.exe install -servicename "MyService" -displayname "My Service" -description "This is my service."
Run Code Online (Sandbox Code Playgroud)

你不需要连接一个ServiceInstaller就可以了--TopShelf为你完成所有这些工作.

  • 确保您的目标是完整的.NET 4.5.2运行时,而不是客户端配置文件. (3认同)

Nik*_*lia 24

所以这是完整的演练:

  1. 创建新的控制台应用程序项目(例如MyService)
  2. 添加两个库引用:System.ServiceProcess和System.Configuration.Install
  3. 添加下面打印的三个文件
  4. 生成项目并运行"InstallUtil.exe c:\ path\to\MyService.exe"
  5. 现在您应该在服务列表中看到MyService(运行services.msc)

*InstallUtil.exe通常可以在这里找到: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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您要为 64 位编译项目,则必须使用适用于 64 位的 InstallUtil.exe,可在此处找到:C:\windows\Microsoft.NET\Framework64\... 32 位版本 (C:\windows \Microsoft.NET\Framework\) 会向您抛出 BadImageFormatException ...... (2认同)

meJ*_*rew 7

这是基于最新的.Net Core 3.1将控制台应用程序转换为 Windows 服务作为工作服务的更新方法。

如果您从 Visual Studio 2019 创建一个工作服务,它将为您提供开箱即用创建 Windows 服务所需的几乎所有内容,这也是您需要更改控制台应用程序以将其转换为 Windows 服务的内容。

以下是您需要做的更改:

安装以下 NuGet 包

Install-Package Microsoft.Extensions.Hosting.WindowsServices -Version 3.1.0
Install-Package Microsoft.Extensions.Configuration.Abstractions -Version 3.1.0
Run Code Online (Sandbox Code Playgroud)

将 Program.cs 更改为具有如下实现:

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>();
                });
    }
}
Run Code Online (Sandbox Code Playgroud)

并添加 Worker.cs ,您将在其中放置将由服务操作运行的代码:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当一切准备就绪并且应用程序已成功构建后,您可以使用sc.exe使用以下命令将控制台应用程序 exe 安装为 Windows 服务:

sc.exe create DemoService binpath= "path/to/your/file.exe"
Run Code Online (Sandbox Code Playgroud)

  • 这应该是最新的答案,并考虑最新的 .netcore 版本。 (2认同)