如何从 .NET Core 2.1/2.2 创建 Windows 服务 [英] How to make a Windows Service from .NET Core 2.1/2.2

查看:26
本文介绍了如何从 .NET Core 2.1/2.2 创建 Windows 服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我需要将 .NET Core 2.1 或 2.2 控制台应用程序转换为 Windows 服务.

Recently I had a need to convert a .NET Core 2.1 or 2.2 console application into a Windows Service.

因为我不需要将此过程移植到 Linux,所以我可以省去我在 StackOverflow 上看到的处理 .NET Framework、.NET Standard 和 .NET Core 的任意组合的多个平台解决方案.

As I didn't have a requirement to port this process to Linux, I could dispense with the multiple platform solutions that I had seen on Stack Overflow that dealt with any combination of .NET Framework, .NET Standard and .NET Core.

推荐答案

在这篇文章中,我将描述将 .NET Core 2.1 或 2.2 进程设置为 Windows 服务所需的步骤.

In this post I will describe the steps required to set up a .NET Core 2.1 or 2.2 process as a Windows Service.

因为我对 Linux 没有要求,所以我可以寻找特定于 Windows 的解决方案.

As I have no requirement for Linux, I could look for a solution that was Windows-specific.

一些挖掘发现了 Steve Gordon 的一些帖子(谢谢!),特别是他介绍 Microsoft.Extensions.Hosting 包和 Windows 托管的地方(点击 此处 用于发布和 此处 为他的 GitHub 示例).

A bit of digging turned up some posts from Steve Gordon (thanks!), in particular where he presents the Microsoft.Extensions.Hosting package and Windows hosting (click here for post and here for his GitHub sample).

以下是所需的步骤:

  • 首先创建一个 .NET Core 控制台应用程序.
  • 将语言版本设置为至少 7.1 以支持 Main 方法的异步任务.(从项目设置-> 构建-> 高级-> 语言设置访问语言版本.
  • 添加 Microsoft.Extensions.Hosting 和 System.ServiceProcess.ServiceController 包.
  • 编辑项目 .csproj 文件并将其包含在 PropertyGroup 中:<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
  • 确保您在 PropertyGroup Exe</OutputType>

现在转到 Program.cs 并复制以下内容:

Now go to Program.cs and copy the following:

using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace AdvancedHost
{
    internal class Program
    {
        private static async Task Main(string[] args)
        {
            var isService = !(Debugger.IsAttached || args.Contains("--console"));

            var builder = new HostBuilder()
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<LoggingService>();
                });

            if (isService)
            {
                await builder.RunAsServiceAsync();
            }
            else
            {
                await builder.RunConsoleAsync();
            }
        }
    }
}

此代码将支持交互式调试和生产执行,并运行示例类 LoggingService.

This code will support interactive debugging and production execution, and runs the example class LoggingService.

这是服务本身的骨架示例:

Here is a skeleton example of the service itself:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Concurrent;

namespace AdvancedHost
{
    public class LoggingService : IHostedService, IDisposable
    {

        public Task StartAsync(CancellationToken cancellationToken)
        {
            // Startup code

            return Task.CompletedTask;
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            // Stop timers, services
            return Task.CompletedTask;
        }

        public void Dispose()
        {
            // Dispose of non-managed resources
        }
    }
}

完成项目所需的最后两个文件:

The final two files necessary to complete the project:

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

namespace AdvancedHost
{

    public class ServiceBaseLifetime : ServiceBase, IHostLifetime
    {
        private readonly TaskCompletionSource<object> _delayStart = new TaskCompletionSource<object>();

        public ServiceBaseLifetime(IApplicationLifetime applicationLifetime)
        {
            ApplicationLifetime = applicationLifetime ?? throw new ArgumentNullException(nameof(applicationLifetime));
        }

        private IApplicationLifetime ApplicationLifetime { get; }

        public Task WaitForStartAsync(CancellationToken cancellationToken)
        {
            cancellationToken.Register(() => _delayStart.TrySetCanceled());
            ApplicationLifetime.ApplicationStopping.Register(Stop);

            new Thread(Run).Start(); // Otherwise this would block and prevent IHost.StartAsync from finishing.
            return _delayStart.Task;
        }

        private void Run()
        {
            try
            {
                Run(this); // This blocks until the service is stopped.
                _delayStart.TrySetException(new InvalidOperationException("Stopped without starting"));
            }
            catch (Exception ex)
            {
                _delayStart.TrySetException(ex);
            }
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            Stop();
            return Task.CompletedTask;
        }

        // Called by base.Run when the service is ready to start.
        protected override void OnStart(string[] args)
        {
            _delayStart.TrySetResult(null);
            base.OnStart(args);
        }

        // Called by base.Stop. This may be called multiple times by service Stop, ApplicationStopping, and StopAsync.
        // That's OK because StopApplication uses a CancellationTokenSource and prevents any recursion.
        protected override void OnStop()
        {
            ApplicationLifetime.StopApplication();
            base.OnStop();
        }
    }
}

文件ServiceBaseLifetimeHostExtensions.cs:

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

namespace AdvancedHost
{

    public static class ServiceBaseLifetimeHostExtensions
    {
        public static IHostBuilder UseServiceBaseLifetime(this IHostBuilder hostBuilder)
        {
            return hostBuilder.ConfigureServices((hostContext, services) => services.AddSingleton<IHostLifetime, ServiceBaseLifetime>());
        }

        public static Task RunAsServiceAsync(this IHostBuilder hostBuilder, CancellationToken cancellationToken = default)
        {
            return hostBuilder.UseServiceBaseLifetime().Build().RunAsync(cancellationToken);
        }
    }
}

为了安装、运行或删除服务,我使用了sc"实用程序:

In order to install, run or delete the service I use the 'sc' utility:

sc create AdvancedHost binPath="C:	empAdvancedHostAdvancedHost.exe"

其中 AdvancedHost 是服务名称,binPath 的值是编译后的可执行文件.

where AdvancedHost is the service name and the value for binPath is the compiled executable.

服务创建完成后,启动:

Once the service is created, to start:

sc start AdvancedHost

停止:

sc stop AdvancedHost

最后删除(一旦停止):

And finally to delete (once stopped):

sc delete AdvancedHost

sc 中包含更多功能;只需在命令行上单独输入sc"即可.

There are many more features contained in sc; just type 'sc' alone on the command line.

sc 的结果可以在服务的 Windows 控制面板中看到.

The results of sc can be seen in the services Windows control panel.

这篇关于如何从 .NET Core 2.1/2.2 创建 Windows 服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆