如何托管ASP.NET Core應用到Windows Service中


(此文章同時發表在本人微信公眾號“dotNET開發經驗談”,歡迎右邊二維碼來關注。)

題記:正在構思一個中間件的設計,考慮是否既可以使用最新的技術,也可以兼顧傳統的部署模式。所以有了這個問題(包括衍生問題)的提出和解決方法。

托管到Windows Service中

眾所周知,ASP.NET Core采用了和傳統ASP.NET不同的托管和HTTP處理方式,即把服務器和托管環境完全解耦。

ASP.NET Core內置了兩個HTTP服務器實現,一個是基於libuv實現的Kestrel(支持跨平台),一個是基於Windows HTTP Server API實現的WebListener(僅支持Windows)。

而托管環境可以和服務器不相關,一般情況是自托管,或者托管到IIS/IISExpress中(此處的IIS僅作為反向代理把請求轉發給所使用的服務器實現)。

因此,打算以Windows Service這種比較傳統的方式來部署ASP.NET Core的Web應用也是可行的(本質還是自托管,只是啟動進程並非控制台程序,而是一個Windows Service)。這不,微軟就很貼心的提供了一個Nuget來支持:Microsoft.AspNetCore.Hosting.WindowsServices,它的源碼在:https://github.com/aspnet/Hosting/tree/dev/src/Microsoft.AspNetCore.Hosting.WindowsServices

使用它也很簡單:

  1. 創建一個以.NET Framework為運行時的ASP.NET Core應用,即模版選擇“ASP.NET Core Web Application (.NET Framework)”。
  2. 引用Microsoft.AspNetCore.Hosting.WindowsServices。
  3. 在Program的Main方法中,把默認的host.Run改為host.RunAsService。
  4. 編譯程序后,會在Debug目錄下看到你選用的運行時版本的一個目錄,比如“net46”,在里面會看到編譯好的exe文件和一個類似“win7-x64”的這樣文件夾。
  5. 進入到“win7-x64”文件夾,在命令行執行“sc create MyService binPath = "Full\Path\To\The\Console\file.exe"”,來創建一個Windows Service。注意:binPath必須是全路徑。
  6. 這樣就可以在Windows Service中托管ASP.NET Core應用了。
  7. 如果希望在服務啟動和停止的過程中做一些額外處理,比如記錄日志,那么可以實現一個CustomWebHostService來繼承WebHostService ,並在其中編寫所需的代碼。
  8. 並實現如下的擴展方法:
public static class CustomWebHostWindowsServiceExtensions
{
    public static void RunAsCustomService(this IWebHost host)
    {
        var webHostService = new CustomWebHostService(host);
        ServiceBase.Run(webHostService);
    }
}
host.RunAsCustomService();

把ASP.NET Core應用托管到Windows Service中,就這么簡單!

更多問題?

不過,我想從我的場景來談談為什么我有托管到Windows Service的需求。這幾天在構思一個中間件(包含多個組件)的架構,考慮到初期會以比較傳統的方式來部署,后期有可能跨平台,並且希望組件之間能夠相對獨立和解耦。所以,最自然的想法就是架構設計為微服務,基於ASP.NET Core實現(未來不排除使用其他技術棧)。部署的話,初期分離部署為多個Windows Service,后期也可以很平滑的過度到容器或者類似Service Fabric這樣的微服務運行平台中。

基於這樣的設計考慮,要解決的第一個問題就是是否可以把ASP.NET Core應用托管到Windows Service中(上面已經驗證了),第二個問題是是否可以根據環境條件跑在不同的啟動進程中,第三問題是是否可以同時支持多種運行時。2,3個問題要解決其實也非常簡單。

支持不同啟動方式

第二個問題的解決辦法如下:

  1. 在Program的Main方法中,判斷一下特定的命令行參數,比如“--windows-service”
  2. 以這個參數啟動的情況下,就host.RunAsService,不是的話就host.Run。

就是這么簡單粗暴。

支持不同運行時

.NET Core本來就支持一個項目多個運行時,就算把net46和netcoreapp1.0混合也是可以的。具體方法如下:

  1. 修改project.json文件,在frameworks下額外添加“netcoreapp1.0”。
  2. 把對Microsoft.AspNetCore.Hosting.WindowsServices的依賴移到net46下
  3. 在netcoreapp1.0下添加“Microsoft.NETCore.App”的依賴
  4. 在Program的Main方法中,基於條件編譯的符號來判斷不同的運行時,具體的符號表見:https://docs.microsoft.com/en-us/dotnet/articles/core/tutorials/libraries#how-to-multitarget

示例源代碼

為了避免在文章中貼大段的源代碼,大家轉到GitHub中去看示例代碼吧:https://github.com/heavenwing/HostingAspCoreAsWindowsService


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM