前言 在.NET Core 2.0發佈的時候,博主也趁熱使用ASP.NET Core 2.0寫了一個獨立的博客網站,現如今恰逢.NET Core 3.0發佈之際,於是將該網站進行了升級。 下麵就記錄升級過程中遇到的一些變化和問題。同時也小廣告一波,歡迎大家多來我的博客逛逛:不落閣 - 一個.NET程 ...
前言
在.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來獲取。
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