與時俱進 | 博客現已運行在 .NET Core 3.0 及 Azure 上

  • 2019 年 10 月 7 日
  • 筆記

導語

9月23日,微軟正式發佈了 .NET Core 3.0,這個版本具有大量新功能和改進。我也在第一時間將自己的博客網站更新到了 .NET Core 3.0,並且仍然跑在微軟智慧雲 Azure 國際版的應用服務上。本文總結了我在博客遷移過程中所有的要點。

從 .NET Core 3.0 Preview 8 開始,我一直在研究博客從 .NET Core 2.2 到 .NET Core 3.0的遷移。大多數遷移路徑可以遵循微軟官方文檔。但眾所周知,常規ASP.NET 項目絕不會只使用來自微軟或 .NET 本身的 API 和包。有很多第三方包可能尚未更新以支持 .NET Core 3.0。某些庫仍將在 .NET Core 3.0 上運行,但並不是每個庫都可以完全沒有任何問題地運行。

典型的 ASP.NET Core 項目的遷移可能卡在這些第三方包上,因此請在遷移之前查看這些包是否有新版本發佈。

我不會在這裡重複微軟文檔中已有的遷移步驟。請按照正式文檔上的所有內容首先將項目遷移到 .NET Core 3.0。但是到目前為止,以下內容並不在文檔中,您可能需要注意。

微軟官方遷移文檔:https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.0&tabs=visual-studio

運行時及SDK

.NET Core 3.0 運行時可以和舊版本同時安裝在一台機器上。例如,你可以同時具有 1.1, 2.1, 2.2 以及 3.0 的運行時,互相不會干擾。

對於 SDK,從3.0開始,安裝新版 SDK 會自動卸載舊版本(僅3.0)的SDK,因此你的程序列表裡不會出現一大坨SDK。

可以參閱微軟官方博客對 SDK 安裝改進的說明:https://devblogs.microsoft.com/dotnet/improving-net-core-installation-in-visual-studio-and-on-windows/

要在 Windows Server 的 IIS 上承載一個 .NET Core 3.0 應用,你依然需要安裝 Runtime and Hosting Bundle (ANCM 模塊)。

Visual Studio 及工具

有許多朋友在微信群里問過,為啥安裝了 .NET Core 3.0 SDK,VS里依舊不顯示?這是因為只有最新的16.3版的VS2019才完整支持開發.NET Core 3.0程序。因此請確保你先升級到VS2019 16.3。

至於 Visual Studio Code,無需額外的處理,依舊運行得很香。

C# 8 及工程文件

C# 8 與.NET Core 3.0同時發佈,當前的SDK及編譯器支持最新語法。因此以前我為了讓項目在編譯服務器上通過而採用的變通方案可以刪了:

 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">    <LangVersion>7.3</LangVersion> </PropertyGroup>

被砍的 ASP.NET Core 包

如果你針對 .NET Core 2.x 或者 .NET Standard 2.x 寫了個類庫,正好用到了像這樣的 ASP.NET 包:

<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />

你是肯定找不到他們的3.0版本的,因為大家太喜歡,所以砍了。

詳見官方說明:https://github.com/aspnet/AspNetCore/issues/3756

然而仍然有一些漏網之魚是有3.0版本的,比如這個:

<PackageReference Include="Microsoft.AspNetCore.Http.Features" Version="3.0.0" />

因此,如果你找不到對應包的3.0版本,現在的解決方式也很簡單,直接將他們替換成一個單獨的 Microsoft.AspNetCore.App 的FrameworkRefrence,即可幹掉一切ASP.NET Core的包,就算算有3.0版本也可以無視。

<FrameworkReference Include="Microsoft.AspNetCore.App" />

Json.NET vs System.Text.Json

我個人是個極端微軟主義戰士,倡導儘可能遷移到 System.Text.Json。事實上,我博客除了引用庫依賴以外的用戶代碼里,已經沒有任何 Json.NET 的痕迹了。但是,目前 System.Text.Json 有一些已知的限制和巨坑,比如我在 GitHub 上提出的這個:https://github.com/dotnet/corefx/issues/41102 。諸如此類的問題容易讓你的代碼瞬間爆炸,而你死活不知道為啥。

不拋出異常的代碼也不一定意味着能像以前一樣運行。例如,有一些特殊字符會被轉義。這會讓你的API用戶或者前端程序員爆進ICU。

var obj = new { Id = 1, BlowUp = @"Make things blow / <up>" };  var jsonNetResult = Newtonsoft.Json.JsonConvert.SerializeObject(obj);  var systemTextJsonResult = System.Text.Json.JsonSerializer.Serialize(obj);

這段代碼的結果竟然是:

jsonNetResult

{"Id":1,"BlowUp":"Make \things blow / <up>"}

systemTextJsonResult

{"Id":1,"BlowUp":"Make \things blow / u003Cupu003E"}

因此請格外小心這些轉義,一定要在發佈到正式環境之前用足夠的數據完整測試你的代碼。

此外,不僅僅序列化會爆,反序列化也有行為上的差異,容易讓你996進ICU。

class BlowUp  {      public int Id { get; set; }      public string Name { get; set; }  }  static void Main(string[] args)  {      string rawJson = "{"id":1,"name":"996ICU"}";      var obj1 = Newtonsoft.Json.JsonConvert.DeserializeObject<BlowUp>(rawJson);      var obj2 = System.Text.Json.JsonSerializer.Deserialize<BlowUp>(rawJson);      Console.WriteLine(obj1.Name);      Console.WriteLine(obj2.Name);  }

猜猜結果是啥?

只有 obj1.Name 有值。因為 obj2 的所有屬性都是默認值或null。

這是因為我們傳入的JSON字符串用了小寫開頭的屬性名。Json.NET默認會處理這種情況,但是 System.Text.Json 必須使用這樣的參數:

var obj2 = System.Text.Json.JsonSerializer.Deserialize<BlowUp>(rawJson, new JsonSerializerOptions  {      PropertyNameCaseInsensitive = true  });

在真實項目里,ASP.NET Core Web API 或者異教徒的API產品通常返回小寫開頭的JSON字符串。當我們使用這些API時,System.Text.Json 的默認行為就會讓我們爆進ICU。

就像剛才這兩個例子一樣,新版JSON API有太多意外行為,因此在遷移到 System.Text.Json 前,請確保你有充分的測試數據覆蓋所有情況再上線。

Azure 應用程序監控遷移

請參閱我之前的文章:Migrate Azure Application Insights to ASP.NET Core 3.0

https://edi.wang/post/2019/9/2/migrate-azure-application-insights-to-aspnet-core-30

(中文版還沒來得及翻譯,先湊合看看吧)

Azure DevOps 大爆炸

Azure DevOps 的編譯管線里還沒有部署 .NET Core 3.0,因此目前你提交一個 .NET Core 3.0 的程序到CI管線里肯定編譯不過。解決方案是添加一個安裝 .NET Core 3.0 SDK的步驟。

Azure App Service 大爆炸

Azure App Service 也還沒有部署 .NET Core 3.0。因此如果你直接將項目用默認編譯形式部署在Azure上,會直接產生一個ANCM的啟動異常,爆進ICU。解決方案是使用SCD部署。

如果你使用的是 Azure DevOps,修改發佈參數,添加 SCD 參數,如:–self-contained -r win-x64

結束語

以上就是我遷移 .NET Core 3.0 時遇到的所有問題及技巧。還有很多其他我沒遇到過的場景,歡迎大家留言補充。