.NET Framework時代,.NET 應(yīng)用程序大多直接部署運行在Windows服務(wù)器上。無論部署exe,還是IIS站點、或是Windows Service,編譯后的程序直接copy、簡單配置部署上即可。
有了.NET Core之后,.NET應(yīng)用程序完美支持跨平臺部署。
支持跨平臺部署運行,.NET 5/.NET Core的應(yīng)用程序面臨著多平臺,多場景的部署需求。比如說:部署在Windows、Linux、MaxOS...,OS層面是否需要部署.NET Runtime運行時,.NET Runtime運行時的版本選擇,等等。
因此,今天我們研究一下.NET 5/.NET Core應(yīng)用程序的部署發(fā)布。
1. 以自包含的方式發(fā)布應(yīng)用程序
這種模式包含.NET運行時和應(yīng)用程序及其依賴項的應(yīng)用程序。我們可以在未安裝.NET運行時的操作系統(tǒng)上運行它。
總結(jié)一句話:把.NET Runtime運行時打包到程序運行目錄中,應(yīng)用程序運行的主機不需要安裝.NET Runtime運行時。
2. 以依賴于框架的方式發(fā)布應(yīng)用程序
生成一個僅包含應(yīng)用程序本身及其依賴項的應(yīng)用程序。應(yīng)用程序的運行環(huán)境必須單獨安裝.NET運行時。
總結(jié)一句話:不包含.NET Runtime運行時,只有應(yīng)用程序本身和依賴的應(yīng)用程序。應(yīng)用程序運行的主機需要單獨安裝應(yīng)用程序所需的.NET Runtime運行時。
dotnet publish -將應(yīng)用程序及其依賴項發(fā)布到指定的文件夾中,以方便后續(xù)部署到目標托管系統(tǒng)。
關(guān)于dotnet publish的使用說明,可以參考以下鏈接:https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish?WT.mc_id=DT-MVP-5003918
dotnet publish [<PROJECT>|<SOLUTION>] [-c|--configuration <CONFIGURATION>] [-f|--framework <FRAMEWORK>] [--force] [--interactive] [--manifest <PATH_TO_MANIFEST_FILE>] [--no-build] [--no-dependencies] [--no-restore] [--nologo] [-o|--output <OUTPUT_DIRECTORY>] [-p:PublishReadyToRun=true] [-p:PublishSingleFile=true] [-p:PublishTrimmed=true] [-r|--runtime <RUNTIME_IDENTIFIER>] [--self-contained [true|false]] [--no-self-contained] [-v|--verbosity <LEVEL>] [--version-suffix <VERSION_SUFFIX>]dotnet publish -h|--help
dotnet publish 將編譯應(yīng)用程序,讀取其在項目文件中指定的依賴項,然后將結(jié)果文件集發(fā)布到目錄中。輸出包括以下內(nèi)容:
從上述描述中,我們可以發(fā)現(xiàn),通過dotnet publish指令,我們可以編譯應(yīng)用程序,生成并輸出指定運行環(huán)境的交付物。
我們新建一個.NET 5的Console應(yīng)用程序,同時引用Newtonsoft.Json Nuget包。
Main函數(shù)的代碼:
using System;
namespace NET5PublishExample{ class Program { static void Main(string[] args) { var msg = Newtonsoft.Json.JsonConvert.SerializeObject('Hello .NET 5!'); Console.WriteLine(msg); Console.ReadKey(); } }}
首先,編譯一下這個工程dotnet build,這一步很重要。然后,使用命令行執(zhí)行dotnet publish指令:
我們看一下F:\GitHub\Source\Repos\NET5PublishExample\bin\Debug\net5.0\publish\目錄下生成的文件:
正如上面所說,輸出包括以下內(nèi)容:
同時,還生成了一個Windows平臺的可執(zhí)行文件:NET5PublishExample.exe,雙擊可以執(zhí)行:
另外,使用dotnet NET5PublishExample.dll,也可以直接執(zhí)行:
然后有幾個疑問:
帶著這2個問題,我們繼續(xù)往下研究?
自包含的方式發(fā)布應(yīng)用程序,依賴于框架的方式發(fā)布應(yīng)用程序。這兩種發(fā)布模式默認情況下都會生成特定于平臺的可執(zhí)行文件和跨平臺二進制文件。
1. 可執(zhí)行文件
可執(zhí)行文件不是跨平臺的。它們特定于操作系統(tǒng)和CPU體系結(jié)構(gòu)。因為Windows和linux下的可執(zhí)行文件的結(jié)構(gòu)和內(nèi)容是不同的,所以可執(zhí)行文件是分操作系統(tǒng)的。
這里我們示例2個平臺的可執(zhí)行文件:
① windows-x64平臺
② Linux-x64平臺
使用的dotnet publish指令 dotnet publish -r linux-x64 --self-contained false
生成的可執(zhí)行文件:
2. 跨平臺的二進制文件
將應(yīng)用程序發(fā)布為依賴于框架的dll文件形式時,就會創(chuàng)建跨平臺的二進制文件。該dll文件以項目命名。例如,如果您有一個名為應(yīng)用程序NET5PublishExample,文件名為NET5PublishExample.dll創(chuàng)建。
以這種方式發(fā)布的應(yīng)用程序dotnet <filename.dll>可以通過命令運行,可以在任何平臺上運行。
以自包含的方式發(fā)布應(yīng)用會生成特定于平臺的可執(zhí)行文件。
輸出發(fā)布文件夾包含應(yīng)用程序的所有組件,包括.NET庫和目標運行時。該應(yīng)用程序與其他.NET應(yīng)用程序隔離,并且不使用本地安裝的.NET運行時。因此無需下載并安裝.NET 運行時。
可執(zhí)行二進制文件針對指定的目標平臺生成。例如,如果您有一個名為NET5PublishExample的應(yīng)用程序,并且發(fā)布了Windows的自包含可執(zhí)行文件,則會創(chuàng)建NET5PublishExample.exe文件。對于Linux或macOS發(fā)布,將創(chuàng)建一個NET5PublishExample文件。目標平臺和體系結(jié)構(gòu)-r <RID>由dotnet publish命令的參數(shù)指定。有關(guān)RID的更多信息,請參見.NET RID目錄。
如果應(yīng)用程序具有特定于平臺的依賴項,例如包含特定于平臺的依賴項的NuGet程序包,則這些依賴項將與應(yīng)用程序一起復(fù)制到publish文件夾中。
這種模式的優(yōu)勢有哪些呢?
同時也帶來了以下問題:
例如:
示例1:發(fā)布一個獨立的應(yīng)用程序,創(chuàng)建macOS 64位可執(zhí)行文件,同時包含了.NET 運行時
dotnet publish -r osx-x64
生成的文件列表如下:包含macOS 64可執(zhí)行文件NET5PublishExample,以及包含了對應(yīng)macOS 64平臺下的.NET 運行時
示例2:發(fā)布一個獨立的應(yīng)用程序,創(chuàng)建Windows 64位可執(zhí)行文件,同時包含了.NET 運行時
dotnet publish -r win-x64
生成的文件列表如下:包含Windows 64可執(zhí)行文件NET5PublishExample.exe,以及包含了對應(yīng)Windows 64平臺下的.NET 運行時
發(fā)布為依賴框架的應(yīng)用程序是跨平臺的,并且不包含.NET運行時。應(yīng)用程序的運行需要單獨安裝指定版本的.NET運行時。
應(yīng)用程序的跨平臺二進制文件可以使用dotnet <filename.dll>命令運行,并且可以在任何平臺上運行。如果應(yīng)用程序使用具有特定于平臺的實現(xiàn)的NuGet包,則所有平臺的依賴項都將與應(yīng)用程序一起復(fù)制到publish文件夾中。
可以通過將-r <RID> --self-contained false參數(shù)傳遞給dotnet publish命令來為特定平臺創(chuàng)建可執(zhí)行文件。當-r參數(shù)被省略,為當前平臺創(chuàng)建一個可執(zhí)行文件。具有目標平臺特定于平臺的依賴關(guān)系的任何NuGet軟件包都將復(fù)制到publish文件夾中。
這種模式帶來的優(yōu)勢有:
同時也帶來了以下問題:
例如:
示例1:發(fā)布一個當前平臺的依賴框架的跨平臺應(yīng)用程序,不包含.NET 運行時,將與dll文件一起創(chuàng)建一個針對當前平臺的可執(zhí)行文件。
dotnet publish
使用dotnet NET5PublishExample.dll,可以直接運行(本機已經(jīng)安裝.NET運行時,NET5PublishExample.dll是跨平臺的二進制文件)
示例2:發(fā)布一個依賴框架的跨平臺應(yīng)用程序(Linux 64位),不包含.NET 運行時,將創(chuàng)建一個Linux 64位可執(zhí)行文件以及dll文件。
dotnet publish -r linux-x64 --self-contained false
使用dotnet NET5PublishExample.dll,可以直接運行(本機已經(jīng)安裝.NET運行時,NET5PublishExample.dll是跨平臺的二進制文件)
通過將應(yīng)用程序程序集編譯為ReadyToRun(R2R)格式,可以改善.NET應(yīng)用程序的啟動時間和延遲。R2R是一種提前(AOT)編譯的形式。
R2R二進制文件通過減少應(yīng)用程序加載時即時(JIT)編譯器需要完成的工作量來提高啟動性能。與JIT產(chǎn)生的代碼相比,二進制文件包含相似的本機代碼。
但是,R2R二進制文件較大,因為它們既包含中間語言(IL)代碼(某些情況下仍然需要此代碼)和同一代碼的本機版本。僅當發(fā)布針對特定運行時環(huán)境(RID)(例如Linux x64或Windows x64)的應(yīng)用程序時,R2R才可用。
總結(jié)一下:通過R2R方式,可以直接將代碼編譯為Native Code,減少.NET 程序第一次加載時JIT編譯帶來的性能消耗,以提升.NET應(yīng)用的首次加載性能。類似于ngen的程序集預(yù)加載。關(guān)于Ngen可以參考這個鏈接:ngen
對應(yīng)的dotnet publish指令選項: dotnet publish -c Release -r win-x64 -p:PublishReadyToRun=true
以上是.NET 5/.NET Core應(yīng)用程序的發(fā)布部署的一些研究和分享。
推薦一個不錯的知識鏈接:https://docs.microsoft.com/en-us/dotnet/core/deploying/#publish-framework-dependent?WT.mc_id=DT-MVP-5003918
聯(lián)系客服