此文章同時(shí)發(fā)表在本人微信公眾號“dotNET開發(fā)經(jīng)驗(yàn)談”易茬,歡迎右邊二維碼來關(guān)注疫蔓。)
題記:正在構(gòu)思一個(gè)中間件的設(shè)計(jì)腐巢,考慮是否既可以使用最新的技術(shù),也可以兼顧傳統(tǒng)的部署模式腻脏。所以有了這個(gè)問題(包括衍生問題)的提出和解決方法鸦泳。引用博客http://www.cnblogs.com/redmoon/p/6051281.html
托管到Windows Service中
眾所周知,ASP.NET Core采用了和傳統(tǒng)ASP.NET不同的托管和HTTP處理方式永品,即把服務(wù)器和托管環(huán)境完全解耦做鹰。
ASP.NET Core內(nèi)置了兩個(gè)HTTP服務(wù)器實(shí)現(xiàn),一個(gè)是基于libuv實(shí)現(xiàn)的Kestrel(支持跨平臺)鼎姐,一個(gè)是基于Windows HTTP Server API實(shí)現(xiàn)的WebListener(僅支持Windows)钾麸。
而托管環(huán)境可以和服務(wù)器不相關(guān)更振,一般情況是自托管,或者托管到IIS/IISExpress中(此處的IIS僅作為反向代理把請求轉(zhuǎn)發(fā)給所使用的服務(wù)器實(shí)現(xiàn))饭尝。
因此肯腕,打算以Windows Service這種比較傳統(tǒng)的方式來部署ASP.NET Core的Web應(yīng)用也是可行的(本質(zhì)還是自托管,只是啟動進(jìn)程并非控制臺程序钥平,而是一個(gè)Windows Service)实撒。這不,微軟就很貼心的提供了一個(gè)Nuget來支持:Microsoft.AspNetCore.Hosting.WindowsServices涉瘾,它的源碼在:https://github.com/aspnet/Hosting/tree/dev/src/Microsoft.AspNetCore.Hosting.WindowsServices知态。
使用它也很簡單:
- 創(chuàng)建一個(gè)以.NET Framework為運(yùn)行時(shí)的ASP.NET Core應(yīng)用,即模版選擇“ASP.NET Core Web Application (.NET Framework)”睡汹。
- 引用Microsoft.AspNetCore.Hosting.WindowsServices肴甸。
- 在Program的Main方法中寂殉,把默認(rèn)的host.Run改為host.RunAsService囚巴。
- 編譯程序后,會在Debug目錄下看到你選用的運(yùn)行時(shí)版本的一個(gè)目錄友扰,比如“net46”彤叉,在里面會看到編譯好的exe文件和一個(gè)類似“win7-x64”的這樣文件夾。
進(jìn)入到“win7-x64”文件夾村怪,在命令行執(zhí)行“sc create MyService binPath = "Full\Path\To\The\Console\file.exe"”秽浇,來創(chuàng)建一個(gè)Windows Service。注意:binPath必須是全路徑甚负。
這樣就可以在Windows Service中托管ASP.NET Core應(yīng)用了柬焕。 - 如果希望在服務(wù)啟動和停止的過程中做一些額外處理,比如記錄日志梭域,那么可以實(shí)現(xiàn)一個(gè)CustomWebHostService來繼承WebHostService
斑举,并在其中編寫所需的代碼。
并實(shí)現(xiàn)如下的擴(kuò)展方法:
public static class CustomWebHostWindowsServiceExtensions
{
public static void RunAsCustomService(this IWebHost host)
{
var webHostService = new CustomWebHostService(host);
ServiceBase.Run(webHostService);
}
}
host.RunAsCustomService();
把ASP.NET Core應(yīng)用托管到Windows Service中病涨,就這么簡單富玷!
更多問題?
不過既穆,我想從我的場景來談?wù)劄槭裁次矣型泄艿絎indows Service的需求赎懦。這幾天在構(gòu)思一個(gè)中間件(包含多個(gè)組件)的架構(gòu),考慮到初期會以比較傳統(tǒng)的方式來部署幻工,后期有可能跨平臺励两,并且希望組件之間能夠相對獨(dú)立和解耦。所以囊颅,最自然的想法就是架構(gòu)設(shè)計(jì)為微服務(wù)当悔,基于ASP.NET Core實(shí)現(xiàn)(未來不排除使用其他技術(shù)棧)工三。部署的話,初期分離部署為多個(gè)Windows Service先鱼,后期也可以很平滑的過度到容器或者類似Service Fabric這樣的微服務(wù)運(yùn)行平臺中俭正。
基于這樣的設(shè)計(jì)考慮,要解決的第一個(gè)問題就是是否可以把ASP.NET Core應(yīng)用托管到Windows Service中(上面已經(jīng)驗(yàn)證了)焙畔,第二個(gè)問題是是否可以根據(jù)環(huán)境條件跑在不同的啟動進(jìn)程中掸读,第三問題是是否可以同時(shí)支持多種運(yùn)行時(shí)。2宏多,3個(gè)問題要解決其實(shí)也非常簡單儿惫。
支持不同啟動方式
第二個(gè)問題的解決辦法如下:
在Program的Main方法中,判斷一下特定的命令行參數(shù)伸但,比如“--windows-service”
以這個(gè)參數(shù)啟動的情況下肾请,就host.RunAsService,不是的話就host.Run更胖。
就是這么簡單粗暴铛铁。
支持不同運(yùn)行時(shí)
.NET Core本來就支持一個(gè)項(xiàng)目多個(gè)運(yùn)行時(shí),就算把net46和netcoreapp1.0混合也是可以的却妨。具體方法如下:
修改project.json文件饵逐,在frameworks下額外添加“netcoreapp1.0”。
把對Microsoft.AspNetCore.Hosting.WindowsServices的依賴移到net46下
在netcoreapp1.0下添加“Microsoft.NETCore.App”的依賴
在Program的Main方法中彪标,基于條件編譯的符號來判斷不同的運(yùn)行時(shí)倍权,具體的符號表見:https://docs.microsoft.com/en-us/dotnet/articles/core/tutorials/libraries#how-to-multitarget
示例源代碼
為了避免在文章中貼大段的源代碼,大家轉(zhuǎn)到GitHub中去看示例代碼吧:https://github.com/heavenwing/HostingAspCoreAsWindowsService