.NET 8/9 升級筆記 - 舊版 .NET 程式相容問題
| | | 3 | |
微軟上週發佈了一個 ASP.NET Core 資安漏洞 CVE-2025-55315,若 ASP.NET Core 網站用 Kestrel 執行,.NET 需升級到 8.0.21 / 9.0.10 才安全。
趁著升級,順手整理主機安裝的 .NET 版本。隨著 .NET 版本更新,我一路裝了 .NET 6/7/8/9,應用程式清單一堆:(註:我之前沒學明白,其實裝了 SDK 就不用裝 ASP.NET Core 執行階段、.NET 桌面執行階段)

.NET 的 Runtime 除了從網站下載安裝檔,也可透過 Visual Studio 安裝:

總之,一番清理後我只留了 .NET 8.0.21 (.NET SDK 8.0.121) 跟 .NET 9.0.10 (.NET SDK 9.0.306) 兩種 SDK:(註:原本的 .NET SDK 9.0.304 跟 Visual Studio 2022 有依賴關係,升級 VS2022 時會一併更新到 9.0.306)

(碎唸:.NET 的版號順序有點亂,如第一張圖,SDK 8.0.121 比 SDK 8.0.415 新,這...)
用 dotnet --list-runtimes 檢查,整理後只留 8.0.21 跟 9.0.10,清爽多了。

但問題來了,解除安裝一時爽,把 .NET 6 Runtime 刪了,之前用 .NET 6 編譯的程式還能跑嗎?
繼續討論前先復習基本知識:使用 dotnet 命令列工具發行 .NET 6 專案,.NET 發行專案有兩種模式:
- Self-Contained
發佈結果自帶 .NET Runtime 檔案,目標主機不管有無安裝 .NET SDK 或 .NET Runtime 都不影響執行 - Framework-Dependent (--no-self-contained)
發佈結果只包含程式及其參照程式庫,運行主機必須安裝所需的 .NET SDK 或 .NET Runtime 版本
若是後者,移除 .NET 6 SDK/Runtime 後程式就無法執行了,會出現 You must install or update .NET to run this application. 錯誤訊息。

此時還有一招可以免重新編譯,強迫使用 .NET 8 Runtime 執行 .NET 6 編譯的程式。原則上 .NET 8 可向前相容 .NET 6,有很大的機會可以無痛跨版執行。
要改變執行 Runtime 版本可修改 <組件名稱>.runtimeconfig.json,把其中的 6.0 改成 8.0:

BUT! 並非所有 .NET 執行檔都可透過修改 runtimeconfig.json 改變 Runtime 版本,若當初發佈時選了 -p:PublishSigleFile,*.runtimeconfig.json/*.deps.json 會被編譯到執行檔 參考,無法直接修改調整。若排除直接改二進位內容等暴力破解手段,就只能用新版 .NET 重新編譯發佈或安裝 .NET 6 Runtime,或是使用下面介紹的 RollForward 大絕。
由於 .NET 6+ 不像 .NET 4.X 採就地更新(In-Place Update,安裝 4.8 後,4.6.2 自動改用 4.8 執行),故必須考慮 Framework-Dependent 模式對 .NET Runtime 的依賴。.NET Runtime 基本上會保持一定程度的向前相容性,通常 .NET 7 相容 .NET 6 大部分的 API,.NET 8 也會相容 .NET 7,難免會有一些 Breaking Change,但有很大的機率可以直接執行 (延伸閱讀:.NET Runtime 相容性)。當然用新版 .NET 重新編譯並測試過是最理想的升級新版做法,但 .NET 有提供一些直接改用新版 .NET Runtime 執行的做法,除了上面介紹的修改 runtimeconfig.json,還有一招是使用 RollForward 設定,
以 .NET 8.0.20 為例,8 是主版本、0 是次版本、20 是修補版本,RollForward 屬性有以下選項:
- Minor (預設值):若請求的次版本不存在,則升級至下一個可用的較高次版本(並使用該次版本中最高的修補版本);若請求的次版本存在,則使用 LatestPatch 策略。
- Major:若請求的主版本不存在,則升級至下一個可用的較高主版本(使用該主版本中最低的次版本及最高的修補版本);若請求的主版本存在,則使用 Minor 策略。
- LatestPatch:升級至請求的主版本與次版本中可用的最高修補版本。此選項會停用次版本升級。
- LatestMinor:即使請求的次版本存在,也會升級至請求主版本中可用的最高次版本(並使用該次版本中最高的修補版本)。
- LatestMajor:即使請求的主版本存在,也會升級至可用的最高主版本(並使用該主版本中最高的次版本與修補版本)。
- Disable:不進行升級,只綁定至指定版本。不建議一般使用,因為此選項會停用升級至最新修補版本的能力。僅建議用於測試用途。
因為使用 Major 或 LatestMajor 可以在沒有安裝指定版本 .NET Runtime 時改用有安裝的下一版或最高版 .NET Runtime。RollForward 可在 .csproj 設定:
<PropertyGroup>
<RollForward>LatestMinor</RollForward>
</PropertyGroup>
編譯產生 runtimeconfig.json 時會多一個 rollForward:
{
"runtimeOptions": {
"tfm": "net6.0",
"rollForward": "LatestMinor",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
}
}
}
如此當執行時若發現沒有所需的 .NET Runtime,程式會嘗試改用最新版的 .NET Runtime。另外,也可在執行時加上 --roll-forward 參數 MyApp.exe --roll-forward LatestMajor。
還有一招,可以完全不動專案或啟動參數 - 設定環境變數 $env:DOTNET_ROLL_FORWARD='LatestMajor'(PowerShell) 或 SET DOTNET_ROLL_FORWARD LatestMajor(CMD) 也可以讓 .NET 6 程式改用 .NET 8 或 9 執行,理論上可解決大部分的相容問題。(提醒:直接改用新版 .NET Runtime 仍有低機率出現不相容問題)
最後簡單說一下 Windows 如何選擇要裝哪種 .NET Runtime 套件,在 .NET 下載頁,左邊是 SDK,右邊是 Runtime (執行時期),共有三區(如下圖):

若你是要跑 ASP.NET Core,建議安裝 Hosting Bundle [1] (在應用程式安裝清單的名字叫 .NET X.X Windows Server Hosting),它除了 ASP.NET Core Runtime,還包含 IIS 的 ASP.NET Core 模組 (ANCM),用 IIS 跑 ASP.NET Core 必備。如果非常確定不會用 IIS 跑 ASP.NET Core,可以下載純 ASP.NET Core Runtime [2];若要跑 .NET 6+ 寫的 Windows Form/WPF,則可下載 .NET 桌面執行階段 [3];若很確定只會跑 .NET Console 程式,下載 .NET Runtime 就好 [4]。(註:ASP.NET Core 或 桌面 Runtime 內含 .NET Runtime)
Upgrading .NET to 8.0.21/9.0.10 is crucial for ASP.NET Core security; Tips about keeping existing apps running after upgraded.
Comments
# by Lauyea
想請問Azure 上面的 Web App 要如何更新?我問GPT它說可以 1. 等Azure 自動更新 2. 改用 Docker(但我現在不是) 3. 指定 runtime,用 self-contained 發布方式 這樣只能走第三步了?沒有人遇到同樣問題嗎?
# by Jeffrey
to Lauyea,依據微軟 App Service team 的公告 https://azure.github.io/AppService/2025/10/20/dotnet-on-windows.html ,Azure 10/20 已在進網站前的 HTTP Load Balancer 加上修補擋下針對該漏洞的攻擊,即使 Runtime 還沒更新也不會受此漏洞影響。 We have deployed a patch to our HTTP load balancer infrastructure (aka Front Ends) to mitigate CVE-2025-55315. This patch protects Web apps, Function apps and Logic apps (standard) on both Windows and Linux instances from the impact of this CVE, even if the underlying .NET runtime remains on an affected version.
# by Lauyea
了解,謝謝黑大。