[ASP.NET] ASP.NET 5 的核心:K (KRE, KVM, KPM)

ASP.NET 5 的核心架構,除了徹底拔除 System.Web 的相依之外,為了要讓它更小更快,微軟為 ASP.NET 5 發展了一個新的核心執行引擎,其專案代號為 Project K。

ASP.NET 5 的核心架構,除了徹底拔除 System.Web 的相依之外,為了要讓它更小更快,微軟為 ASP.NET 5 發展了一個新的核心執行引擎,其專案代號為 Project K,它包含了三個部份:

  • 一個執行引擎 (runtime engine),這個引擎負責帶起 ASP.NET 所需的 CLR 與 Core CLR 環境,並將 ASP.NET 5 程式交給所屬的 Hosting Service 接管執行,我們現在在 ASP.NET 5 專案中看到的 Console App, Web 及 Class Library 都要由它來帶出,專案內也可以依自己所需設定 Hosting Service 的代理引擎,例如 Self-hosting, Kestrel (for Linux) 或是 IIS (Helios)。
  • 一個組件管理工具 (package management tool) ,它負責處理應用程式所需套件的管理工作,包含下載,檢測與更新的,在 Visual Studio 內我們使用的是 NuGet,但 Project K 在 NuGet 之上建構了一個專屬的管理工具,它還是使用 NuGet 的技術,只是它更適合 Project K。
  • 一個版本管理工具 (version management),它負責處理執行引擎的版本管理,開發人員可以自由選擇要安裝,使用與更新何種版本的 Runtime Engine,而且可同時支援 x86/x64 與 CLR/CoreCLR。

K的執行引擎稱為 KRE (K Runtime Environment),KRE 負責了應用程式所需要的執行引擎環境,它能同時使用於 Core CLR 與 Mono 的功能,現階段 Mono 提供了 KRE 可執行於 Linux/Mac 上的能力 (未來或許會有官方非 Mono 的版本),KRE 由 KLR.exe 帶起,不過 KLR 並不負責 CLR 的工作,它只是一個靴帶程式 (Bootstrap Program),將 KRE 所需要的環境載入,並隨後將控制權交給 KRE 後即結束,因此不同的平台若要 Hosting KRE 的話,只要在該平台上發展自己的 KLR,將 KRE 帶入即可。

KRE 在被 KLR 帶入之後,會開始啟動一個載入器 (Loader),由 project.json 內所定義的 Runtime 類型決定載入何種平台,現階段 ASP.NET 5 的平台分類 aspnet50 及 aspnetcore50,分別代表 CLR 與 Core CLR,CLR 仍然由 .NET Framework 本身的 CLR 處理,若是 Core CLR,則會載入 CoreCLR.dll,由 Core CLR 的核心進行處理及程式碼載入的工作,而目前 CLR 和 Core CLR 的組件相容性不同,CLR 可用的組件無法使用於 Core CLR,因此若要將程式由 CLR 移轉到 Core CLR,還要多處理組件相容性的問題。

KRE 有相當強的 Dependency Injection 特性,這些相依性的載入與偵測由 Rosyln Loader 負責, KRE 新增的 Assembly Netural Interface 功能即是由 Rosyln Loader 處理,可以讓組件內含自己所需的 interface,而不再需要跟著一個 interface 的來源組件 (例如只用了一個很大的 DLL 的 interface,卻要連同那個大 DLL 一起部署和載入,並不經濟)。

 

KRuntime layer diagram

在 ASP.NET vNext 的教學中,我們看到要啟動一支程式可以用 k run 或是 k web 來執行,實際上這個 k 並不是執行檔,而是一個 cmd 檔,它的內容是:


 @Echo OFF
SETLOCAL
SET ERRORLEVEL=
:: K [command] [args]
:: command : Required - Name of the command to execute
:: args : Optional - Any further args will be passed directly to the command.
:: e.g. To compile the app in the current folder:
:: C:\src\MyApp\>K build
IF "%K_APPBASE%"=="" (
SET "K_APPBASE=%CD%"
)
"%~dp0klr" --appbase "%K_APPBASE%" %K_OPTIONS% "Microsoft.Framework.ApplicationHost" %*
exit /b %ERRORLEVEL%
ENDLOCAL

其實它是用來呼叫 KLR.exe,並且將它丟給 Microsoft.Framework.ApplicationHost 組件的一個靴帶而已,Microsoft.Framework.ApplicationHost 內建了一個 run 模式,專門供給 Console Application,其他的則由 project.json 來設定,像在 ASP.NET MVC 6 的 project.json 內可以設不同的 command line 是一樣的。

這類靴帶型的啟動方式也可以用在 KRE 套件管理的服務,KRE 套件管理服務稱為 K Package Manager (KPM),kpm 本身也只是一個靴帶式的 cmd 檔而已:


@Echo OFF
SETLOCAL
SET ERRORLEVEL=
"%~dp0klr" --appbase "%CD%" %K_OPTIONS% --lib "%~dp0lib\Microsoft.Framework.PackageManager" Microsoft.Framework.PackageManager %*
exit /b %ERRORLEVEL%
ENDLOCAL

kpm 帶出的是 Microsoft.Framework.PackageManager 這個組件,負責管理應用程式的套件,例如 kpm restore 可以還原應用程式本身的組件,kpm build 可以將應用程式建造成可部署的 NuGet Package,kpm pack 可以封裝應用程式等等。

KRE 本身不具自身的版本管理功能,它必須依賴 KRE Version Manager (KVM),kvm 是一個獨立的程式,用來處理 KRE 的版本管理,包含安裝,升級,套用特定版本的 KRE 均要由它來管理,不過它也是一支靴帶程式 (kvm.cmd):


@Echo off

PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0kvm.ps1' %*"

IF EXIST "%USERPROFILE%\.kre\run-once.cmd" (
  CALL "%USERPROFILE%\.kre\run-once.cmd"
  DEL "%USERPROFILE%\.kre\run-once.cmd"
)

這次它呼叫的不再是套件,而是一支 PowerShell 指令碼,名稱為 kvm.ps1,裡面包含了呼叫相關的 .NET Framework 組件,到 NuGet 上抓取 Package 以及安裝等動作,若對它的作法有興趣的人可以在安裝好 KVM 後,到 KVM 的目錄 (%USER_DIR%\.kre\bin) 即可看到這兩個檔案。

若要安裝 KRE,首先必須安裝 KVM,安裝的方法很簡單,只要下這個指令:


@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/aspnet/Home/master/kvminstall.ps1'))"

它就會幫我們下載 KVM:

image

安裝完畢後關閉 cmd,然後再啟動一次讓變數生效,接著,下 kvm install latest 指令,它就會幫我們下載最新版本的 KRE,依我下筆此刻,KRE 的 master 版本是 1.0.0-beta1:

image

預設情況下,kvm 會下載 x86 CLR 版本的 KRE,若要安裝 x64 以及 Core CLR 的 KRE,則要下這些指令:


kvm install latest -x86 -r CLR (x86 CLR, default)
kvm install latest -x86 -r CoreCLR (x86 Core CLR)
kvm install latest -amd64 -r CLR (x64 CLR)
kvm install latest -amd64 -r CoreCLR (x64 Core CLR)

image

KRE 下載完成後,我們就可以啟動程式了,我在 C:\ 下新增了一個 KRE-ConsoleApp 目錄,並配置了兩個檔案,這兩個檔案可由 ASP.NET vNext 的 GitHub 取得:https://github.com/aspnet/Home/tree/master/samples/ConsoleApp

image

然後用 KRE 執行它,你會發現它不需要編譯就能執行:

image

喔,其實它並不是不需要編譯,而是在 KRE 被帶起來時,動態呼叫 Rosyln Compiler 進行編譯,這部份的工作由 Microsoft.Framework.Runtime 進行,Microsoft.Framework.Runtime 處理了大多數的 KRE 應用程式的編譯,相依偵測與執行環境建置的工作,因此我們不太需要煩惱這些,只要確定專案的 project.json 的資訊充份即可。

或許你會發現一件事,在我們執行的過程中,都沒有特別去做加入參考的動作,連 project.json 內也只有一個 System.Console 組件的參考而已,KRE 還是會自己回到 KRE 本身所在的目錄去搜尋,並找到適當的組件載入 (這個動作目前只有 Core CLR 會做,若是 CLR 的則會自動載入 .NET Framework 本身的組件),但 KRE 要做到的一件重要功能,就是希望組件能夠隨著應用程式散布,為了達到這個功能,我們就要利用 kpm 來做。一開始什麼都沒有的時候,先下 kpm restore,它會還原 System.Console.dll 組件以及它的相依組件:

image

這些組件會放置到 KPM 的目錄下的 packages 子目錄內:

image

接著我們再下 kpm pack,由 kpm 來封裝檔案:

image

它會依照各組件的路徑產生各組件的 package,package 內還會依平台來分,aspnetcore50 是給 Core CLR 使用的檔案,output 資料夾的內容基本上就已經可以直接拿到主機上部署…

image

但若是想要將應用程式 (尤其是 DLL) 封裝成 NuGet 的套件,這就要用到 kpm build 了:

image

它會將應用程式編譯成可執行檔 (DLL),並且將 DLL 及產生的如 PDB 或資訊檔封裝成 NuGet 的套件。編譯引擎是由 Rosyln 提供,現階段只支援 C#,未來應該會擴大到 Visual Basic 和其他語言。

在 KRE 的世界裡,可執行檔基本上只有 DLL,沒有 EXE,因為 KRE 的應用程式都必須透過 KLR.exe 啟動,並且由 KRE 載入,不是由作業系統直接呼叫,所以應用程式都是以 DLL 來呈現,即便是要直接執行,也還是要由 k.cmd 來啟動,如同前面啟動 Console App 一樣,不過 Microsoft.Framework.ApplicationHost 會自動偵測 Program.Main 的存在,而且 Main 也不一定要用 static 來宣告,這點是和一般的應用程式些許不同之處。

對了,KRE 目前還是在快速開發的階段,在 github.com/aspnet/Home 裡的版本進度幾乎每天更新,下筆此刻的最新開發版本為 1.0.0-rc1-10804,穩定版本則為 1.0.0-beta1,這個數字會持續改變:

image

使用 kvm install lastest 指令只能抓到 aspnetmaster 的版本 (也就是 beta-1),若你想當個勇者,或是你像我一樣想搶先使用更新的版本,有兩個方法能達成,第一個是修改 NuGet 的 config,把來源改為 dev 版本的來源,在 ASP.NET 的 Github Wiki 上可以看到作法,但我有個更快的作法,就是執行下列指令,重新安裝 kvm:


@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/aspnet/Home/dev/kvminstall.ps1'))"

然後下 kvm upgrade 指令,它會升級預設的 KRE (x86 CLR),你也可以使用下列指令更新其他的 KRE:


kvm upgrade -x86 -r CLR (x86 CLR, Default)
kvm upgrade -x86 -r CoreCLR (x86 Core CLR)
kvm upgrade -amd64 -r CLR (x64 CLR, Default)
kvm upgrade -amd64 -r CoreCLR (x64 Core CLR)

如果想知道目前系統內有哪些 KRE,除了可以到 Visual Studio 內,打開任一個 ASP.NET 5 的專案,在專案屬性內就能看到外:

image

還可以下 kvm list 來查:

image

KRE 是作為 ASP.NET 5 的核心引擎,只要寫 ASP.NET 5 應用程式,基本上就得和它打交道,不過它使用上並沒有那麼困難,頂多就是指令要記一下,但比起一堆命令列工具嚇死人的參數數量,KRE/KVM/KPM 算是好很多的了 :)

 

Reference: https://github.com/aspnet/Home/wiki/KRuntime-structure