

使用 dotnet 命令列工具發行 .NET 6 專案
source link: https://blog.darkthread.net/blog/dotnet6-publish-notes/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

.NET 5 時介紹過用 Visual Studio 發行 .NET 5 專案,.NET 6 這篇改整理 .NET CLI (dotnet 命令列工具) 發行技巧。
主要參考來源為微軟文件 - .NET application publishing overview
dotnet publish 產生的執行程式有兩種形式:可執行檔 (在 Windows 為 .exe,在 Linux/macOS 則是與專案同名的無附檔名檔案) 或跨平台程式檔 (.dll,用 dotnet appName.dll 執行)。
可執行檔種類取決執行 dotnet publish 所在的平台,加上 -r win-x64、-r linux-x64 則可產生特定平台用的可執行檔,win-x64 是所謂 RID ( .NET 6 支援的 RID 清單),不同平台又再有 Self-Contained 及 Framework-Dependent 兩種選擇。
- Self-Contained
部署結果包含 .NET Runtime,部署對象不需先安裝 .NET SDK 或 .NET Runtime,缺點是檔案較多,且每支程式重複自帶 Runtime 會多佔用磁碟空間 - Framework-Dependent
只包含程式及其參照程式庫,部署對象必須裝好 .NET SDK 或 .NET Runtime
由可執行檔 vs 跨平台程式檔,Self-Contained vs Framework-Dependent 兩個維度排列組合,dotnet publish 參數分別為:(適用 .NET Core 3.1、.NET 5/6,排除 .NET 2.1)
- Framework-Dependent 跨平台程式檔
dotnet publish -c Release -p:UseAppHost=false - Framework-Dependent 可執行檔
dotnet publish -c Release -r <RID> --no-self-contained
dotnet publish -c Release -r <RID> --self-contained false
dotnet publish -c Release (未指定 -r 時,產出目前所在平台的可執行檔) - Self-Contained 可執行檔
dotnet publish -c Release -r <RID> --self-contained - Self-Contained 跨平台程式檔
無此組合
先列出主要可用參數,後面再補充說明
- PublishSingleFile
- UseAppHost
- IncludeNativeLibrariesForSelfExtract
- IncludeAllContentForSelfExtract
- IncludeSymbolsInSingleFile
- PublishReadyToRun
- EnableCompressionInSingleFile
以上參數有兩種設定方式,直接寫在 .csproj:
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>dotnet_publish_test</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishSingleFile>false</PublishSingleFile>
</PropertyGroup>
或是 dotnet publish 加上 -p:PublishSingleFile=true 設定,它將覆寫 .csproj 裡的設定:
dotnet publish -c Release -r win-x64 --no-self-contained -p:PublishSingleFile=true
簡單介紹各參數用法。
如果覺得 Publish 結果包含一堆 DLL 太亂,有個 PublishSingleFile 參數可將所有 DLL 整併成單一執行檔,部署時一檔搞定。但 --self-contained 時會內含 .NET Runtime,執行檔大小常超過 70MB,有個 PublishTrimmed 參數可排除沒用到 DLL,執行檔有時可瘦身一半以上。但偵測未用 DLL 很難完全精準,瘦身版務必仔細測試再上線。
PublishSingleFile 預設只會整併 .NET 寫的 DLL (Managed DLL),DLL 依附的原生函式庫仍保留獨立檔案形式,IncludeNativeLibrariesForSelfExtract 參數能將這部分也合併進執行檔,執行時原生 DLL 檔將匯出到特定目錄(在 Windows 為 %TEMP%/.net、Linux 及 MacOS 為 $HOIME/.net,或可使用 DOTNET_BUNDLE_EXTRACT_BASE_DIR 環境變數指定)。依實測,沒用到原生 DLL,PublishSingleFile 併入的 Managed DLL 可直接載入記憶體使用,檔案不需落地;但如用到 IncludeNativeLibrariesForSelfExtract 併入原生 DLL,則需一併指定 IncludeAllContentForSelfExtract,將原生 DLL 跟參照 .NET DLL 都匯出到 %TEMP%/.net、$HOME/.net 或 DOTNET_BUNDLE_EXTRACT_BASE_DIR 指定目錄,才能正確載入原生 DLL。實地觀察可在 .net 目錄看到匯出檔案:
PublishSingleFile 合併成單一檔案後,仍會有 .pdb 檔,使用 IncludeSymbolsInSingleFile 則可合併 .pdb 內容,實現真正單一檔案。
若有特殊 DLL 檔不要併入執行檔但要放進發行目錄,可修改 csproj:
<ItemGroup>
<Content Update="Plugin.dll">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
</ItemGroup>
另外,PublishReadyToRun 參數可指定預先完成 JIT 編譯,程式碼體積會變大,但可節省程式啟動時間。
.NET 6 起,多了 EnableCompressionInSingleFile 參數可壓縮併入執行檔的 DLL,進一步縮小體積。但程式啟動時需先在記憶體中解壓縮,要付出效能上的代價,建議視應用情境取捨。
[2021-12-14 補充] dotnet publish 預設包含編譯程序,還有個 --no-build 參數可直接使用 obj 下的內容。若發行程序有使用混淆器處理 obj 目錄檔案,--no-build 可避免混淆過的檔案被覆寫,但此時不可用 PublishTrimmed。(感謝讀者 Peter Cheng 分享)
最後來個範例整理:
- dotnet publish -c Release
不含 .NET Runtime,同時產出 .dll 及 .exe (或是所在平台的可執行檔),部署對象需安裝 .NET Runtime/SDK - dotnet publish -c Release -p:UseAppHost=false
不含 .NET Runtime,只產出 .dll,部署對象需安裝 .NET Runtime/SDK,使用 dotnet appName.dll 執行 - dotnet publish -c Release -r win-x64 --self-contained
包含 Windows x64 .NET Runtime 以及 .exe 可執行檔 - dotnet publish -c Release -r linux-x64 --no-self-contained
產生 64 位元 Linux 用的 .exe 可執行檔,部署對象需安裝 .NET Runtime/SDK - dotnet publish -c Release -r linux-x64 --self-contained
包含 64 位元 Linux .NET Runtime 以及 Linux 用的可執行檔 - dotnet publish -c Release -r win-x64 --self-contained -p:PublishSingleFile=true
將 Windows x64 .NET Runtime、參照的 .NET .dll,以及程式本身打包成一個 .exe 可執行檔 (大小可能超過 70MB),但參照程式庫附屬的原生程式庫仍維持個別檔案 - dotnet publish -c Release -r win-x64 --self-contained -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:IncludeAllContentForSelfExtract=true 同 6,但將參照程式庫附屬的原生程式庫也包進 .exe,實測 IncludeNativeLibrariesForSelfExtract 需配合 IncludeAllContentForSelfExtract 參數才能正確執行
- dotnet publish -c Release -r win-x64 --self-contained -p:PublishSingleFile=true -p:PublishTrimmed=true
同 6,但進行程式瘦身,剔除沒用到的程式庫部分,.exe 甚至可縮小一半以上。但有可能出現誤刪,部署前請慎重測試
Recommend
-
12
我們最近有專案需要發行一個用 ASP.NET Core 5 開發的網站,有經驗的人應該知道,當網站正在執行時,尤其是 Windows 作業系統,過程中所有 *.dll 檔案都會被鎖定,無法成功覆蓋檔案,以致於自動部署失敗。今天這篇文章我打算來分享幾個常見的作法...
-
7
每次要開始寫一個 Node.js 搭配 TypeScript 的專案,都沒有一個能讓自己滿意的專案範本,不然就是網路上經常找到不完整的參考文件。這篇文章我打算建立一個 Node.js 搭配 TypeScri...
-
8
我們在團隊中開發 Angular 應用程式,經常需要同步每個成員的程式碼格式,與其訂定 Coding Style (代碼風格),倒不如直接用工具強制所有成員用一致的風格進行程式碼排版。本篇文章我將示範用 hus...
-
14
我一年大概都會幫幾家企業導入 Azure DevOps Server 平台,最近幫客戶導入的過程遇到了一個難題。一個方案檔中有 9 個專案,其中有 4 個 .NET Framework 4.7.2 類別庫專案、1 個 .NET Framework 4.7.2 的 ASP.NET Web Forms 專案、2 個 .NET Core 2.1 類別庫專...
-
9
早期 Angular CLI 建立的專案都有內建 TSLint 與 codelyzer,但從 Angular CLI v11 開始建議大家開始轉移到
-
3
如何在專案中透過 .NET CLI 管理專案的本地工具 (.NET Local Tool) 我們在使用 .NET CLI 開發專案的時候,經常會需要安裝一些 .NET 全域工具 (.NET Global Tool),但是安裝全域工具有個小缺點,那就是這些工具會需要被註冊到 PATH 環境變...
-
7
舊專案沒做的,就把他做起來吧!一個 Rails 專案,有三台機器,每次部屬分別要手動部屬,但其實這個可以做自動化三台機器分別是不同的權限使用但都吃同一個專案,並非 load balance 那種情況這邊我只用自己的電腦來做,所以這三台機器都分...
-
15
大家都知道 Go 語言的開發環境是非常的快速,但是如果你想要在開發的時候,修改程...
-
9
SonarQube Docker 安裝與 .NET 6+ 專案掃瞄-黑暗執行緒 SonarQube 是一套程式碼品質掃瞄工具,可以分析你的程式的寫法是否存在 Bug、漏洞或
-
3
使用 dotnet user-secrets 儲存專案專屬秘密設定(API Key、密碼)-黑暗執行緒 看程式範例學到用 .NET Secret Manager 儲存秘密設定(如 API Key)的小技巧。 參考文件:
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK