The Will Will Web | ASP.NET Core 的 Microsoft.AspNetCore.App 中繼套件載入問題與心得分享

The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

ASP.NET Core 的 Microsoft.AspNetCore.App 中繼套件載入問題與心得分享

我前陣遇到一個 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.AppVersion 屬性為 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.0Bug,而且也在 2.1.1 版正式被修復

解決方案

解決方法其實很簡單,既然是 Bug,就沒甚麼好說的了,直接用新版執行 .NET Core 即可。同時,也建議將快取中的 NuGet 套件刪除,以免載入到有問題的 NuGet 套件。刪除的命令如下:

dotnet nuget locals all --clear

學習心得

追查這個問題,讓我了解到幾個有趣的細節。

  1. .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,專案什麼都不用改,直接重新建置與發行,就會是新版了!

  2. 我要怎樣才能知道 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}");
    

相關連結