通过Visual Studio中的Windows Service模板,我么可以创建.NET Framework版本的Windows Service,网络上对此已有详细且丰富的各路教程。但在我们升级到.NET Core 3.1或.NET 6后(这里仅讨论两个LTS版本),情况发生了相当大的变化。我们需要根据新的Worker Service模板,基于BackgroundService这个类来创建最新版本的Windows Service。

.NET 6学习笔记(2)——通过Worker Service创建Windows Service-LMLPHP

某软的官方文档更新的很快,文档中列出的创建Windows Service的必要条件都已经是6.0或更新。那是不是说.NET Core 3.1就无法创建呢?答案当然不是。今天我们就稍作修改,创建3.1版本的Windows Service。

.NET Core 3.1作为LTS(Long-term support)版本,是存在大量基于该版本的生产项目的,有时候条件不允许立刻升级到VS2022和.NET 6.0。所以本篇我们将使用VS2019,首先找到Worker Service模板,如果我们仔细观察,会发现除了Windows平台,更多了Linux和macOS的支持。

.NET 6学习笔记(2)——通过Worker Service创建Windows Service-LMLPHP

点击两次Next按钮后,选择.NET Core 3.1版本创建工程。默认仅包含Program和Worker两个cs文件。接下来我们通过NuGet安装Microsoft.Extensions.Hosting.WindowsService包。最新的版本是6.0,且同时依赖6.0版的Microsoft.Extension.Hosting。这里我们有两个选择,第一是在NuGet界面的下拉框中,选择安装3.1.17版本的WindowsService包,保持和默认Hosting包的版本相同。第二是将两者都升级到最新的6.0版本。所幸.NET的向后兼容做的不错,在这里我选择升级。在完成后的简单测试中,无论是部署在.NET 6 Runtime或.NET Core 3.1 Runtime的机器上,均可正常工作。当前状态应该如下图所示。

.NET 6学习笔记(2)——通过Worker Service创建Windows Service-LMLPHP

此时我们可以开始创建业务类了,就是你想用Service干点啥,在本篇的示例中,我只想躺平……疫情期间,不要用眼过度和上头648充值抽卡,打游戏实在是极其健康的选择了。

    public class LieFlatService
    {
        public static int Count { get; set; }
        public string LieFlat()
        {
            return $"Lie flat and play PS4 & Switch... {++Count}";
        }
    }

接着我们通过继承自BackgrounService的Worker类来调用LieFlatService实现躺平。真的是啥也不干,就是每隔一秒宣告一下躺平。

    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        private readonly LieFlatService _lieFlatSrvice;

        public Worker(LieFlatService lieFlatService, ILogger<Worker> logger)
        {
            _lieFlatSrvice = lieFlatService;
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                string message = _lieFlatSrvice.LieFlat();
                _logger.LogWarning(message);
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
        }
    }

然后我们还要修改一下Program类,通过UseWindowsService扩展方法将我们这个Console程序配置成Windows Service类型。如果我们之前选择WindowsServices 3.1的包,除了不能方便的设置SeviceName,其他倒是没啥区别。在CreateHostBuilder方法中,记得注册Worker和LieFlatService类型供.NET内置的依赖注入(Dependency Injection)框架使用。

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args)
                .UseWindowsService(o =>
            {
                o.ServiceName = "Lie Flat Service";
            })
                .Build()
                .Run();
        }

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

代码部分至此就全部完成了。相对于.NET Framework的Windows Service,调试起来要容易的多,就直接当成Console程序Debug就行了。部署的操作也很简单,首先在project文件上右键选择发布到文件夹。

.NET 6学习笔记(2)——通过Worker Service创建Windows Service-LMLPHP

通常默认的发布配置就可以了,点击发布按钮之后,会在项目的bin\Release\netcoreapp3.1\win-x64\publish\目录下生成如下文件。如果修改发布文件选择Self Contained,则可以脱离对部署环境是否安装.NET的依赖,缺点就是会生成一大堆文件。

.NET 6学习笔记(2)——通过Worker Service创建Windows Service-LMLPHP

我们可以将publish文件夹拷贝到想要的位置,然后用admin权限打开PowerShell,通过命令行来创建Windows Service。

sc.exe create "Lie Flat Service" binpath="C:\Users\dell\Desktop\publish\NetCoreWorkerService.exe"

此时打开Services界面,将创建的Lie Flat Service启动。

.NET 6学习笔记(2)——通过Worker Service创建Windows Service-LMLPHP

再打开Event Viewer检查Windows Logs,就可以发现Lie Flat Service发出的躺平宣言了。

.NET 6学习笔记(2)——通过Worker Service创建Windows Service-LMLPHP

删除Windows Service需要通过stop和delete两个命令。

.NET 6学习笔记(2)——通过Worker Service创建Windows Service-LMLPHP

本篇我们介绍了如何在.NET Core 3.1(.NET 6.0也几乎相同)的环境下创建Windows Service。同时.NET 4.5.2, .NET 4.6和.NET 4.6.1将于2022年4月26日终止支持。升级吧同学们。

示例代码:

https://github.com/manupstairs/NetCoreWorkerService

manupstairs/WorkerServiceTest1 (gitee.com)

以下链接,是MS Learn上Windows开发的入门课程,单个课程三十分钟到60分钟不等,想要补充基础知识的同学点这里:

开始使用 Visual Studio 开发 Windows 10 应用

开发 Windows 10 应用程序

编写首个 Windows 10 应用

创建 Windows 10 应用的用户界面 (UI)

增强 Windows 10 应用的用户界面

在 Windows 10 应用中实现数据绑定

03-20 15:19