我前陣遇到一個 ASP.NET Core 2.0 專案,在我安裝完 .NET Core 2.1 SDK 之後,卻發生網站無法正常運作的問題。經過一番研究之後,發現了一些有趣的現象,特此紀錄這段學習歷程。
重現問題
首先,要能重現這個問題,必須符合以下環境要求:
- 已安裝 .NET Core SDK 2.1.300 ( .NET Core Runtime 2.1.0 )
- 已安裝 .NET Core SDK 2.1.302 ( .NET Core Runtime 2.1.2 )
用以下命令建立 ASP.NET Core 2.1 的 MVC 專案
dotnet new mvc -n mvc20
使用 Visual Studio Code 開啟 mvc20
目錄。
建立 global.json
設定檔,並設定 SDK 版本為 2.1.300
( .NET Core 2.1.0 ),代表我想用舊版的 .NET Core SDK 執行 ASP.NET Core 應用程式。
dotnet new globaljson --sdk-version 2.1.300
除了建立 global.json
之外,也可以直接修改 mvc20.csproj
並指定 Microsoft.AspNetCore.App
的 Version
屬性為 2.1.0
,這樣也可以重現問題。總之就是維持原有應用程式使用舊版的 NuGet 套件執行。
然後執行
dotnet run
執行的過程中,請手動修改 Views/Home/Index.cshtml
引發 View 自動重新編譯。此時到瀏覽器「重新整理」網頁,就會看到以下錯誤:
The type 'RazorViewAttribute' exists in both 'Microsoft.AspNetCore.Mvc.Razor, Version=2.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' and 'Microsoft.AspNetCore.Mvc.Razor, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'
發生原因
從 .NET Core 2.0 開始,有個 Roll forward 機制,他會自動搜尋目前的 .NET Core Runtime 是否有新版本,如果有新的 minor (次版號) 版本,就會自動選用最新的版本來載入,如果有新的 patch (修訂號) 自然也是。也就是說,如果系統中安裝了 .NET Core 2.0 與 2.1 版本,預設會自動選用最新版本 2.1 來執行。
備註:依據 語意化版本 2.0.0 中的定義,版本編號為 主版號(major).次版號(minor).修訂號(patch)
。
以我們的這個例子來說,我的主機安裝了 2.1.0 與 2.1.1 版本,但是我們卻限定了 .NET Core SDK 使用舊版,照理說他不會去找新版的 NuGet 套件才對。但這個問題已經被確認為 2.1.0
的 Bug,而且也在 2.1.1
版正式被修復。
解決方案
解決方法其實很簡單,既然是 Bug,就沒甚麼好說的了,直接用新版執行 .NET Core 即可。同時,也建議將快取中的 NuGet 套件刪除,以免載入到有問題的 NuGet 套件。刪除的命令如下:
dotnet nuget locals all --clear
學習心得
追查這個問題,讓我了解到幾個有趣的細節。
-
在 .csproj
檔案中,並沒有指定 Microsoft.AspNetCore.App
中繼套件的版本號!
意思也就是說,當專案透過 dotnet run
執行的時候,會以 .NET Core Runtime 預設的 Microsoft.AspNetCore.App
套件版本來載入。但我要怎樣知道他載入哪些套件與版本呢?
我從 dotnet build -v d
輸出的建置紀錄中,找到許多 MSBuild 的執行細節,其中找到一個 Sdk.DefaultItems.targets
檔案。循著蛛絲馬跡找到 C:\Program Files\dotnet\sdk\2.1.300\Microsoft.NETCoreSdk.BundledVersions.props
檔案,裡面定義了 BundledAspNetCoreAllPackageVersion
屬性。此時真相大白,原來Microsoft.AspNetCore.App
中繼套件的預設版本號,是跟著 .NET Core SDK 一起走的!
所以,以後我們只要安裝了新版本的 .NET Core SDK,專案什麼都不用改,直接重新建置與發行,就會是新版了!
-
我要怎樣才能知道 Microsoft.AspNetCore.App
中繼套件到底載入了那些組件?
如果你想知道 Microsoft.AspNetCore.App 到底包含哪些相依的 NuGet 套件,只要到 NuGet Gallery 查詢即可。但如果想找到實際載入了哪些組件與版本,可以參考以下範例程式:
var referencedAssemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
foreach (var assembly in referencedAssemblies)
Console.WriteLine($"{assembly.Name} {assembly.Version}");
相關連結