首页 学海无涯 .NET Core 博客升级到.NET Core 3.0的变化和问题
博客升级到.NET Core 3.0的变化和问题
摘要 就在微软发布.NET Core 3.0 一周后,本博客也由原来的ASP.NET Core 2.0升级到3.0,本文主要介绍升级过程中遇到的问题和一些变化。

Program.cs变化

WebHostBuilder变为HostBuilder,ASP.NET Core 3.0使用通用主机,而主机配置方式也有所改变,主要集中通过ConfigureWebHostDefaults方法。以下是升级前后的代码:

//升级前:ASP.NET Core 2.0
WebHost.CreateDefaultBuilder(args)
    .UseUrls("http://127.0.0.1:5002")
    .UseStartup<Startup>()
    .ConfigureLogging(logging =>
    {
        logging.ClearProviders();
        logging.SetMinimumLevel(LogLevel.Trace);
    })
    .UseNLog();

//升级后:ASP.NET Core 3.0
Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<Startup>()
        .UseUrls("http://127.0.0.1:5002")
        .ConfigureLogging(logging =>
        {
            logging.ClearProviders();
            logging.SetMinimumLevel(LogLevel.Trace);
        })
        .UseNLog();
    });

Startup.cs变化

配置服务方面:AddControllersWithViews替代了原来的AddMVC。

配置管道方面:UseMVC、UseSignalR统一替换为UseEndpoints,此外增加了UseRouting,UseAuthentication、UseAuthorization必须位于UseRouting和useEndpoints之间。

//升级前
app.UseAuthentication();
app.UseSignalR(routes =>
{
    routes.MapHub<ChatRoom>("/chatroom");
});
app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

//升级后
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
    endpoints.MapHub<ChatRoom>("/chatroom");
});

QQ登录问题(同时也介绍如何使用nupkg文件)

升级到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文件

下载完成后,随便放一个文件夹下,打开VS=》工具=》选项=》Nuget包管理=>程序包源,添加一个程序包源,路径写nupkg所在文件夹


点击确定后,再使用Nuget包管理器,切换到刚才添加的程序包源,就可以使用对应的包了。


用法和之前差不多,只是有两处细微改动:


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中配置。如下所示:

//升级前
services.AddMvc()
    .AddJsonOptions(options =>
    {
        options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); //序列化时key为驼峰样式
        options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
        options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
        options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;    //忽略循环引用
    });

//升级后(需要引入Microsoft.AspNetCore.Mvc.NewtonsoftJson包)
services.AddControllersWithViews()
    .AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); //序列化时key为驼峰样式
        options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
        options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
        options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;    //忽略循环引用
    });

EFCore客户端求值

EF Core 3.0不再支持客户端求值,需要Linq查询出来后再手动运算。

//升级前
detailModel.SimilarArticles = await _dbContext.Article
    .Where(s => s.Status == (int)CommonStatus.Valid && StringSimilarity.Calculate(article.Title, s.Title) > 0.3m && s.Id != article.Id)
    .Select(s => new Article()
    {
        Id = s.Id,
        CreateTime = s.CreateTime,
        Title = s.Title
    })
    .OrderBy(s => Guid.NewGuid())
    .Take(8)
    .ToListAsync();

//升级后
var similarArticles = await _dbContext.Article
    .Where(s => s.Status == (int)CommonStatus.Valid && s.Id != article.Id)
    .Select(s => new Article()
    {
        Id = s.Id,
        CreateTime = s.CreateTime,
        Title = s.Title
    })
    .ToListAsync();
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是一样的。


更多问题待定............

版权声明:本文由不落阁原创出品,转载请注明出处!

本文链接:http://www.leo96.com/article/detail/47

来说两句吧

该文章已禁止评论

最新评论

暂无评论,大侠不妨来一发?