使用.NET Core创建Windows服务(一) - 使用官方推荐方式
原文:Creating Windows Services In .NET Core – Part 1 – The “Microsoft” Way
創(chuàng)建Windows服務(wù)來(lái)運(yùn)行批處理任務(wù)或者運(yùn)行后臺(tái)任務(wù),是一種非常常見(jiàn)的模式,但是由于云服務(wù)(Amazon Lambda, Azure WebJobs以及Azure Functions)的激增,你可能不會(huì)經(jīng)常使用Windows服務(wù)了。個(gè)人而言,我非常喜歡使用Azure WebJobs, 因?yàn)槲铱梢灾苯泳帉?xiě)一個(gè)控制臺(tái)程序,而不需要考慮如何云中運(yùn)行它,一個(gè)批處理文件可以將其裝換成一個(gè)自動(dòng)化任務(wù),并且可以保證7*24小時(shí)的運(yùn)行。
但是也許你還沒(méi)有使用云服務(wù),或者你有一堆要作為Windows服務(wù)運(yùn)行的舊版應(yīng)用程序需要轉(zhuǎn)換為.NET Core, 但是不能完全將他們轉(zhuǎn)換為“無(wú)服務(wù)器”(serverless)應(yīng)用。那么這邊文章就是適合你的。
在許多方面,.NET Core中的Windows服務(wù)和.NET Framework中的Windows服務(wù)完全相同。但是,在編寫(xiě)服務(wù)的時(shí)候,你可能會(huì)遇到一些小問(wèn)題。此外,本文中,我們僅介紹“Microsoft”方式的Windows服務(wù)創(chuàng)建,在后續(xù),我會(huì)繼續(xù)介紹如何使用第三方庫(kù)TopShelf來(lái)簡(jiǎn)化這該過(guò)程。
由于Visual Studio沒(méi)有提供創(chuàng)建Windows服務(wù)的模板,所以我們需要通過(guò)創(chuàng)建控制臺(tái)程序的方式來(lái)創(chuàng)建一個(gè)Windows服務(wù)。
創(chuàng)建完成之后,我們需要安裝一個(gè)Nuget程序包,這個(gè)程序包會(huì)將一些Windows特定的API添加到.NET Core中,這些API實(shí)際上已經(jīng)在完整框架中提供了,但是其中許多是Windows特有的,例如Windows服務(wù)。因此, 它們并沒(méi)有包含在.NET Core的基礎(chǔ)庫(kù)中,但是可以通過(guò)將Nuget程序包的方式引入到.NET Core中。
Install-Package Microsoft.Windows.Compatibility以上引入的Nuget程序包中,最讓我們感興趣的是ServiceBase類(lèi)。這是一個(gè)用于編寫(xiě)Windows服務(wù)的基類(lèi),它提供了一系列的事件鉤子,包含服務(wù)啟動(dòng)、結(jié)束、暫停等。
下面呢,我們將在代碼中創(chuàng)建一個(gè)類(lèi),這個(gè)類(lèi)負(fù)責(zé)將一些簡(jiǎn)單的日志輸出到一個(gè)臨時(shí)文件中。我們將使用這個(gè)例子來(lái)了解其中的原理。我們的代碼如下:
class LoggingService : ServiceBase {private const string _logFileLocation = @"C:\temp\servicelog.txt";private void Log(string logMessage){Directory.CreateDirectory(Path.GetDirectoryName(_logFileLocation));File.AppendAllText(_logFileLocation, DateTime.UtcNow.ToString() + " : " + logMessage + Environment.NewLine);}protected override void OnStart(string[] args){Log("Starting");base.OnStart(args);}protected override void OnStop(){Log("Stopping");base.OnStop();}protected override void OnPause(){Log("Pausing");base.OnPause();} }所以這里你會(huì)注意到,我們的類(lèi)是繼承了ServiceBase類(lèi),并且我們重寫(xiě)了幾個(gè)事件方法,輸出了一些日志。在服務(wù)啟動(dòng)時(shí),會(huì)觸發(fā)OnStart事件,在服務(wù)終止的時(shí)候,會(huì)觸發(fā)OnStop事件。這里我們不應(yīng)該將過(guò)于繁重的任務(wù)放置在OnStart事件中來(lái)處理。
如果我們想從Main方式中啟動(dòng)這個(gè)服務(wù),代碼非常的簡(jiǎn)單。
static void Main(string[] args) {ServiceBase.Run(new LoggingService()); }以上就是全部代碼。
在發(fā)布服務(wù)的時(shí)候,我們不可能僅依靠Visual Studio來(lái)構(gòu)建我們所需要的服務(wù),我們還需要專(zhuān)門(mén)針對(duì)Windows運(yùn)行時(shí)進(jìn)行構(gòu)建。為此,我們需要在項(xiàng)目根目錄的命令提示符下運(yùn)行以下命令。注意,這里我們傳入了一個(gè)-r標(biāo)記來(lái)告訴它要構(gòu)建那個(gè)平臺(tái)。
dotnet publish -r win-x64 -c Release命令運(yùn)行完畢之后,我們可以檢查以下/bin/release/netcoreappX.X/publish目錄,我們可以找到所有的發(fā)布代碼,但是最重要的是,這里我們可以得到一個(gè)可執(zhí)行的exe文件。如果我們不指定運(yùn)行時(shí),我們只會(huì)獲得一個(gè).NET Core的dll程序集,使用這個(gè)程序集,我們是沒(méi)有辦法創(chuàng)建Windows服務(wù)的。
現(xiàn)在我們可以將這個(gè)發(fā)布目錄移動(dòng)帶其他的任何地方,但是現(xiàn)在我們就暫時(shí)使用當(dāng)前的發(fā)布目錄。
下一步,我們需要使用管理員角色打開(kāi)一個(gè)命令提示符,然后輸入一下命令。
sc create TestService BinPath=C:\full\path\to\publish\dir\WindowsServiceExample.exeSC命令是一個(gè)標(biāo)準(zhǔn)的Windows命令(與.NET Core無(wú)關(guān)),它可以用來(lái)安裝Windows服務(wù)。這里我們將我們的測(cè)試服務(wù)命名為T(mén)estService,更重要的是,我們通過(guò)BinPath參數(shù)指定了可執(zhí)行exe文件。
運(yùn)行之后,我們應(yīng)該會(huì)得到以下結(jié)果。
[SC] CreateService SUCCESS然后我們要做的就是啟動(dòng)服務(wù)。
sc start TestService現(xiàn)在我們可以查看一下我們的日志文件,查看服務(wù)的運(yùn)行情況。
如果想要停止并刪除服務(wù),我們可以使用一下命令。
sc stop TestService sc delete TestService在這里,我真的認(rèn)為,使用"Microsoft"的方式注定會(huì)失敗。因?yàn)檎{(diào)試服務(wù)實(shí)在是太繁瑣了。
首先,我們將ServiceBase中重寫(xiě)的方法設(shè)置為受保護(hù),這意味著我們無(wú)法在類(lèi)之外訪問(wèn)它們,這使得調(diào)試它們變得更加困難。這里我發(fā)現(xiàn)最好的方法是為每個(gè)事件提供一個(gè)public方法, 并在受保護(hù)方法中調(diào)用這些public方法來(lái)完成功能,這雖然有點(diǎn)混亂,
public void OnStartPublic(string[] args) {Log("Starting"); }protected override void OnStart(string[] args) {OnStartPublic(args);base.OnStart(args); }但是至少我們可以做如下了事情了。
static void Main(string[] args) {var loggingService = new LoggingService();if (true){loggingService.OnStartPublic(new string[0]);while(true){Thread.Sleep(1000);}}else{ServiceBase.Run(new LoggingService());} }你的另一個(gè)選擇是,在調(diào)試模式下進(jìn)行項(xiàng)目發(fā)布,安裝服務(wù),然后附加調(diào)試器。實(shí)際上,這是Microsoft建議你使用的方式,但是我認(rèn)為這簡(jiǎn)直一團(tuán)糟。
實(shí)際上,我們可以在這里做一些其他非常有用的事情, 比如我們可以通過(guò)創(chuàng)建一個(gè)install.bat批處理文件來(lái)為我們運(yùn)行SC Create命令。但我認(rèn)為,上面我們看到的調(diào)試問(wèn)題,已經(jīng)讓我不再想使用這種方式了。幸運(yùn)的是,有一個(gè)名為T(mén)opshelf的庫(kù)可以幫助我們減輕很多麻煩,在本系列的下一部分中,我們將研究如何它。
總結(jié)
以上是生活随笔為你收集整理的使用.NET Core创建Windows服务(一) - 使用官方推荐方式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
                            
                        - 上一篇: 微软如何利用机器学习改进Win 10更新
 - 下一篇: Tuple VS ValueTuple