.NET 6學習筆記(2)——通過Worker Service建立Windows Service

樓上那個蜀黍發表於2022-03-20

通過Visual Studio中的Windows Service模板,我麼可以建立.NET Framework版本的Windows Service,網路上對此已有詳細且豐富的各路教程。但在我們升級到.NET Core 3.1或.NET 6後(這裡僅討論兩個LTS版本),情況發生了相當大的變化。我們需要根據新的Worker Service模板,基於BackgroundService這個類來建立最新版本的Windows Service。

某軟的官方文件更新的很快,文件中列出的建立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的支援。

點選兩次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的機器上,均可正常工作。當前狀態應該如下圖所示。

此時我們可以開始建立業務類了,就是你想用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檔案上右鍵選擇釋出到資料夾。

通常預設的釋出配置就可以了,點選發布按鈕之後,會在專案的bin\Release\netcoreapp3.1\win-x64\publish\目錄下生成如下檔案。如果修改釋出檔案選擇Self Contained,則可以脫離對部署環境是否安裝.NET的依賴,缺點就是會生成一大堆檔案。

我們可以將publish資料夾拷貝到想要的位置,然後用admin許可權開啟PowerShell,通過命令列來建立Windows Service。

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

此時開啟Services介面,將建立的Lie Flat Service啟動。

再開啟Event Viewer檢查Windows Logs,就可以發現Lie Flat Service發出的躺平宣言了。

刪除Windows Service需要通過stop和delete兩個命令。

本篇我們介紹瞭如何在.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 應用中實現資料繫結

相關文章