ASP.NET Core 2.0升級到3.0的變化和問題


前言

在.NET Core 2.0發布的時候,博主也趁熱使用ASP.NET Core 2.0寫了一個獨立的博客網站,現如今恰逢.NET Core 3.0發布之際,於是將該網站進行了升級。

下面就記錄升級過程中遇到的一些變化和問題。同時也小廣告一波,歡迎大家多來我的博客逛逛:不落閣 - 一個.NET程序員的個人博客

正文

Host變化

Program.cs中WebHostBuilder變為HostBuilder,ASP.NET Core 3.0使用通用主機,而主機配置方式也有所改變,主要集中通過ConfigureWebHostDefaults方法。

以下是升級前后的代碼:

 1 //升級前:ASP.NET Core 2.0
 2 WebHost.CreateDefaultBuilder(args)
 3     .UseUrls("http://127.0.0.1:5002")
 4     .UseStartup<Startup>()
 5     .ConfigureLogging(logging =>
 6     {
 7         logging.ClearProviders();
 8         logging.SetMinimumLevel(LogLevel.Trace);
 9     })
10     .UseNLog();
11 //升級后:ASP.NET Core 3.0
12 Host.CreateDefaultBuilder(args)
13     .ConfigureWebHostDefaults(webBuilder =>
14     {
15         webBuilder.UseStartup<Startup>()
16         .UseUrls("http://127.0.0.1:5002")
17         .ConfigureLogging(logging =>
18         {
19             logging.ClearProviders();
20             logging.SetMinimumLevel(LogLevel.Trace);
21         })
22         .UseNLog();
23     });

Startup.cs變化

配置服務方面:AddControllersWithViews替代了原來的AddMVC。

配置管道方面:UseMVC、UseSignalR統一替換為UseEndpoints,此外增加了UseRouting,UseAuthentication、UseAuthorization必須位於UseRouting和useEndpoints之間。

 1 //升級前
 2 app.UseAuthentication();
 3 app.UseSignalR(routes =>
 4 {
 5     routes.MapHub<ChatRoom>("/chatroom");
 6 });
 7 app.UseMvc(routes =>
 8 {
 9     routes.MapRoute(
10         name: "default",
11         template: "{controller=Home}/{action=Index}/{id?}");
12 });
13 //升級后
14 app.UseRouting();
15 app.UseAuthentication();
16 app.UseAuthorization();
17 app.UseEndpoints(endpoints =>
18 {
19     endpoints.MapControllerRoute(
20         name: "default",
21         pattern: "{controller=Home}/{action=Index}/{id?}");
22     endpoints.MapHub<ChatRoom>("/chatroom");
23 });

QQ登錄問題

升級到ASP.NET Core 3.0后,之前使用的Microsoft.AspNetCore.Authentication.QQ包已經不能正常使用了,經過源碼調試后,我發現是因為對OAuthHandler里面的ExchangeCodeAsync等方法的重寫未生效,導致QQ返回的數據(QQ返回的數據比較特殊)轉化為Json的時候出錯。Nuget上Microsoft.AspNetCore.Authentication.OAuth依舊是2.2.4版本,而Microsoft.AspNetCore.Authentication.MicrosoftAccount、Microsoft.AspNetCore.Authentication.Google等包都已經升級為3.0.0,看了公告https://github.com/aspnet/AspNetCore/issues/10991確實已經改了,只是我們能獲取到的依舊是2.2.4版。

最后在Github上發現了一個第三方認證的集合項目:https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers,在上面找到了QQ登錄的包AspNet.Security.OAuth.QQ

可以看到Nuget上的依舊是2.1.0,這個顯然也不能用,不過myget上已經有3.0.0預覽版的了。

按照PM指令安裝的話會提示找不到這個包對應的版本,最新版是2.1.0,所以這里要手動下載nupkg文件

用法和之前差不多,只是有兩處細微改動:

1.AppId和AppKey改成了統一的ClientId和ClientSercert

2.openid不能映射成自定義Claim名稱,所以后面處理的時候只能通過系統定義的ClaimTypes.NameIdentifier來獲取。

注意:這段圖片設置了防盜鏈,懶得重新上傳,請到作者博客查看詳情:https://www.leo96.com/article/detail/47

Json序列化問題

.NET Core 3.0引入了新的JSON API,並且ASP.NET Core已經移除了Newtonsoft.Json的引用,默認使用System.Text.Json來序列化Json,而新的JSON API主打性能,所以沒有JSON.NET全面。

由於使用了Entity Framework,所以在直接序列化實體類時,導航屬性會出現循環引用的問題,而System.Text.Json並沒有提供解決循環引用問題的相關配置。

在Github上找了下,似乎官方也提到這個問題,但在3.0版本並未提供解決辦法:https://github.com/dotnet/corefx/issues/38579

因此不得不使用原來的JSON API,也就是JSON.NET(Newtonsoft.Json)

要在ASP.NET Core 3.0中使用Newtonsoft.Json,需要安裝Microsoft.AspNetCore.Mvc.NewtonsoftJson包,並在Startup中配置。如下所示:

 1 //升級前
 2 services.AddMvc()
 3     .AddJsonOptions(options =>
 4     {
 5         options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); //序列化時key為駝峰樣式
 6         options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
 7         options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
 8         options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;    //忽略循環引用
 9     });
10 //升級后(需要引入Microsoft.AspNetCore.Mvc.NewtonsoftJson包)
11 services.AddControllersWithViews()
12     .AddNewtonsoftJson(options =>
13     {
14         options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); //序列化時key為駝峰樣式
15         options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
16         options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
17         options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;    //忽略循環引用
18     });

EFCore客戶端求值

EF Core 3.0不再支持客戶端求值,需要Linq查詢出來后再手動運算。

 1 //升級前
 2 detailModel.SimilarArticles = await _dbContext.Article
 3     .Where(s => s.Status == (int)CommonStatus.Valid && StringSimilarity.Calculate(article.Title, s.Title) > 0.3m && s.Id != article.Id)
 4     .Select(s => new Article()
 5     {
 6         Id = s.Id,
 7         CreateTime = s.CreateTime,
 8         Title = s.Title
 9     })
10     .OrderBy(s => Guid.NewGuid())
11     .Take(8)
12     .ToListAsync();
13 //升級后
14 var similarArticles = await _dbContext.Article
15     .Where(s => s.Status == (int)CommonStatus.Valid && s.Id != article.Id)
16     .Select(s => new Article()
17     {
18         Id = s.Id,
19         CreateTime = s.CreateTime,
20         Title = s.Title
21     })
22     .ToListAsync();
23 similarArticles = similarArticles.Where(s => StringSimilarity.Calculate(article.Title, s.Title) > 0.3m).OrderBy(s => Guid.NewGuid()).Take(8).ToList();

以上代碼片段是篩選與某文章標題相似的文章,其中StringSimilarity.Calculate(string,string)方法是客戶端上計算兩個標題相似度的算法,3.0后EF Core已經不支持直接寫到Linq查詢中,會報異常,大概意思是無法翻譯Linq語句。

實際上升級前后兩種寫法生成的SQL是一樣的

更多問題待定,先介紹到這來。

感謝翻閱,敬請斧正!

本文最初發表於:https://www.leo96.com/article/detail/47


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM