通過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分鐘不等,想要補充基礎知識的同學點這裡: