写在前面

微软在更新.Net Core版本的时候,动作往往很大,使得每次更新版本的时候都得小心翼翼,坑实在是太多。往往是悄咪咪的移除了某项功能或者组件,或者不在支持XX方法,这就很花时间去找回需要的东西了,下面是个人在迁移.Net Core WebApi项目过程中遇到的问题汇总:

开始迁移

1 修改*.csproj项目文件

<TargetFramework>netcoreapp2.2</TargetFramework>
修改为
<TargetFramework>netcoreapp3.1</TargetFramework>

2 修改Program

public static void Main(string[] args){CreateWebHostBuilder(args).Build().Run();}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().ConfigureAppConfiguration((hostingContext, config) =>{config.AddJsonFile($"你的json文件.json", optional: true, reloadOnChange: true);}
);

修改为

public static void Main(string[] args){CreateHostBuilder(args).Build().Run();}public static IHostBuilder CreateHostBuilder(string[] args) =>Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>{webBuilder.UseStartup<Startup>().ConfigureAppConfiguration((hostingContext, config)=>{config.AddJsonFile($"你的json文件.json", optional: true, reloadOnChange: true);});});

3.1  修改Startup.ConfigureServices

services.AddMvc();
修改为
services.AddControllers();

3.2 修改Startup.Configure

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
修改为
using Microsoft.Extensions.Hosting;
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

IHostingEnvironment在3.0之后已被标记弃用。

路由配置:

app.UseMvc(routes =>{routes.MapRoute(name: "areas",template: "{area:exists}/{controller=Home}/{action=Index}/{id?}");routes.MapRoute(name: "default",template: "{controller=Home}/{action=Index}/{id?}");});
修改为app.UseRouting();app.UseEndpoints(endpoints =>{endpoints.MapControllers();endpoints.MapControllerRoute(name: "areas",pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");endpoints.MapControllerRoute(name: "default",pattern: "{controller=Home}/{action=Index}/{id?}");});

你以为结束了?还没。

这时候你以为结束了,兴高采烈的去服务器装好runningTime和hosting相应的版本,运行……

HTTP Error 500.30 – ANCM In-Process Start Failure

直接cmd,进入到发布目录,执行

E:\你的路径>dotnet xxx.dll

显示详细错误

而我的相应250代码行是:

services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
//原文地址:https://www.cnblogs.com/EminemJK/p/13206747.html

搜索最新的AutoMapper根本没更新或改变,所以不是这个组件的问题。

尝试下载补丁Windows6.1-KB974405-x64.msu ,无果……

卸载sdk重置,无果……

修改web.config,无果……

修改应用池32位,无果……

最后,查看发布:勾选上【删除现有文件】,解决……

Endpoint contains CORS metadata, but a middleware was not found that supports CORS.

顺利可以启动项目之后,发现有些接口:

2020-06-29 10:02:23,357 [14] ERROR System.String - 全局异常捕捉:异常:Endpoint contains CORS metadata, but a middleware was not found that supports CORS.
Configure your application startup by adding app.UseCors() inside the call to Configure(..) in the application startup code. The call to app.UseAuthorization() must appear between app.UseRouting() and app.UseEndpoints(...).

提示很明显,在.net core 2.2 的时候不是需要强制在指定位置的,

app.UseCors();

在3.0之后需要设置在app.UseRouting和app.UseEndpoints 之间:

app.UseRouting();
//跨域
app.UseCors(one);
app.UseCors(two);
……
app.UseEndpoints(endpoints => ……

The JSON value could not be converted to System.Int32. Path……

运行之后,有些接口没有数据返回,而有些直接报错了。原因又是爸爸把Newtonsoft.Json移除,使用内置的System.Text.Json,所以依赖于Newtonsoft.Json的组件将不可用,那么,只能手动添加。

Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson -Version 3.1.5

然后添加引用

public void ConfigureServices(IServiceCollection services)
{services.AddControllers().AddNewtonsoftJson();……
}

目前还不太建议你使用内置的序列化,因为实在太多功能或方法不支持,详细对比请参考 https://docs.microsoft.com/zh-cn/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to

授权相关

基于策略授权,我想在座的加班狗都是大同小异,在2.2以前:

public class PolicyHandler : AuthorizationHandler<PolicyRequirement>{/// <summary>/// 授权方式(cookie, bearer, oauth, openid)/// </summary>public IAuthenticationSchemeProvider Schemes { get; set; }private IConfiguration _configuration;/// <summary>/// ctor/// </summary>/// <param name="configuration"></param>/// <param name="schemes"></param>/// <param name="jwtApp"></param>public PolicyHandler(IConfiguration configuration, IAuthenticationSchemeProvider schemes){Schemes = schemes;_jwtApp = jwtApp;_configuration = configuration;}/// <summary>/// 授权处理/// </summary>/// <param name="context"></param>/// <param name="requirement"></param>protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PolicyRequirement requirement){var httpContext = (context.Resource as AuthorizationFilterContext).HttpContext;//获取授权方式var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();if (defaultAuthenticate != null){//验证签发的用户信息var result = await httpContext.AuthenticateAsync(defaultAuthenticate.Name);if (result.Succeeded){httpContext.User = result.Principal;//判断是否过期var expirationTime = DateTime.Parse(httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration).Value);if (expirationTime >= DateTime.UtcNow){//你的校验方式//todocontext.Succeed(requirement);}else{HandleBlocked(context, requirement);}return;}}HandleBlocked(context, requirement);}/// <summary>/// 验证失败返回/// </summary>private void HandleBlocked(AuthorizationHandlerContext context, PolicyRequirement requirement){var authorizationFilterContext = context.Resource as AuthorizationFilterContext;authorizationFilterContext.Result = new Microsoft.AspNetCore.Mvc.JsonResult(new UnAuthorizativeResponse()) { StatusCode = 202 };//不要调用 context.Fail(),设置为403会显示不了自定义信息,改为Accepted202,由客户端处理,;context.Succeed(requirement);}}

然后发现升级到3.0之后,

var httpContext = (context.Resource as AuthorizationFilterContext).HttpContext;

3.0不再支持返回AuthorizationFilterContext,而是返回的是RouteEndpoint,这句代码就会报错,所以修改的方式就是注入IHttpContextAccessor,从里面获取HttpContext,这里就不用演示了吧。

并修改PolicyHandler校验失败时候调用的方法:

/// <summary>
/// 验证失败返回
/// </summary>
private void HandleBlocked(AuthorizationHandlerContext context, PolicyRequirement requirement)
{context.Fail();
}

并在Startup.ConfigureServices修改

services.AddHttpContextAccessor();

在AddJwtBearer中

.AddJwtBearer(s =>{//3、添加 Jwt bearer s.TokenValidationParameters = new TokenValidationParameters{ValidIssuer = issuer,ValidAudience = audience,IssuerSigningKey = key,//允许的服务器时间偏差的偏移量ClockSkew = TimeSpan.FromSeconds(5),ValidateLifetime = true};s.Events = new JwtBearerEvents{OnAuthenticationFailed = context =>{//Token 过期 if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)){context.Response.Headers.Add("Token-Expired", "true");} return Task.CompletedTask;},OnChallenge = context =>{context.HandleResponse(); context.Response.StatusCode = StatusCodes.Status200OK;context.Response.ContentType = "application/json";//无授权返回自定义信息context.Response.WriteAsync(JsonConvert.SerializeObject(new UnAuthorizativeResponse()));return Task.CompletedTask;}};});

UnAuthorizativeResponse 是自定义返回的内容。

Startup.Configure中启用Authentication,注意顺序

app.UseRouting();
//跨域
app.UseCors(one);
app.UseCors(two);
……
//启用 Authentication
app.UseAuthorization();
app.UseAuthentication();
app.UseEndpoints(endpoints => ……

文件下载

单独封装的HttpContext下载方法:

public static void DownLoadFile(this HttpContext context,string fileName, byte[] fileByte, string contentType = "application/octet-stream")
{int bufferSize = 1024;context.Response.ContentType = contentType;context.Response.Headers.Append("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(fileName));context.Response.Headers.Append("Charset", "utf-8");context.Response.Headers.Append("Access-Control-Expose-Headers", "Content-Disposition");//context.Response.Headers.Append("Access-Control-Allow-Origin", "*");//使用FileStream开始循环读取要下载文件的内容using (Stream fs = new MemoryStream(fileByte)){using (context.Response.Body){long contentLength = fs.Length;context.Response.ContentLength = contentLength;byte[] buffer;long hasRead = 0;while (hasRead < contentLength){if (context.RequestAborted.IsCancellationRequested){break;}buffer = new byte[bufferSize];//从下载文件中读取bufferSize(1024字节)大小的内容到服务器内存中int currentRead = fs.Read(buffer, 0, bufferSize);context.Response.Body.Write(buffer, 0, currentRead);context.Response.Body.Flush();hasRead += currentRead;}}}
}

下载的时候发现以下错误:Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.

2020-06-29 14:18:38,898 [109] ERROR System.String - System.InvalidOperationException: Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.at Microsoft.AspNetCore.Server.IIS.Core.HttpResponseStream.Write(Byte[] buffer, Int32 offset, Int32 count)at Microsoft.AspNetCore.Server.IIS.Core.WrappingStream.Write(Byte[] buffer, Int32 offset, Int32 count)at DigitalCertificateSystem.Common.Extensions.HttpContextExtension.DownLoadFile(HttpContext context, String fileName, Byte[] fileByte, String contentType) in ……

意思不运行同步操作,修改为:

context.Response.Body.WriteAsync(buffer, 0, currentRead);

这才顺利完成了更新。真的太坑了,不过也感觉微软的抽象化做得很好,按需引入,减少项目的冗余。

更多升级指南请参考“孙子兵法”:

https://docs.microsoft.com/zh-cn/aspnet/core/migration/22-to-30?view=aspnetcore-2.1&tabs=visual-studio

.Net Core 2.2升级3.1的避坑指南相关推荐

  1. Flutter升级到1.12填坑指南

    最近由于项目需要,需要把flutter升级到stable版本,目前的stable版本是1.12.13的hotfix,而我们项目目前的版本是1.7.3.Google在发布flutter 1.12对And ...

  2. ASP.NET Core 3.0 迁移避坑指南

    一.前言 .NET Core 3.0将会在 .NET Conf 大会上正式发布,截止今日发布了9个预览版,改动也是不少,由于没有持续关注,今天将前面开源的动态WebApi项目迁移到.NET Core ...

  3. TiDB 4.0 升级 5.1 二三事——避坑指南

    \n> 原文来源: https://tidb.net/blog/ce260ea4 \n\n# 1. 背景 TiDB 5.1 版本 GA 到目前已经有一年时间,在稳定性.易用性.性能提升等各个方面 ...

  4. 他来了!IDEA 2020.1 新版介绍!不过升级前请注意避坑!

    往期热门文章: 1,<往期精选优秀博文都在这里了!> 2.七个略火的Spring Boot+Vue开源项目! 3.十个你可能不曾用过的Linux命令!巨好用! 4.分库分表  PK  Ne ...

  5. lgg8各个版本_LG G8 展示机 升级安卓10 防踩坑指南

    先来对比下展示机版本信息是不是大体相同再下手 关于手机中,无s/n,无IMEI 安卓9软件版本为G820UM10C,硬件版本1.0 被阉割功能:5G频段wifi,nfc,移动网络(无基带),高分屏,r ...

  6. 将 ASP.NET Core 2.1 升级到最新的长期支持版本ASP.NET Core 3.1

    目录 前言 Microsoft.AspNetCore.Mvc.ViewFeatures.Internal 消失了 升级到 ASP.NET Core 3.1 项目文件(.csproj) Program. ...

  7. .NET Core 1.1 升级公告

    2016年11月16日发布.NET Core 1.1 . 它包括对其他Linux发行版的支持,有很多更新,是当前的第一个版本. 将在下面描述所有这些变化.  它是"Go Live" ...

  8. .net core 1.1 mysql_Asp.net Core 1.1 升级后操作mysql出错的解决办法

    这篇文章主要介绍了Asp.net Core 1.1 升级后操作mysql出错的解决办法,需要的朋友可以参考下 遇到问题 core的版本从1.0升级到1.1,操作mysql数据库,查询数据时遇到Miss ...

  9. vue1升级vue2踩坑指南

    vue1升级vue2踩坑指南 升级原因 版本选择 老的package.json: 新的package.json: vue官方说明 语法/组件使用变化 ready钩子 $index & $key ...

最新文章

  1. php flock 死锁了,php – 防止由flock引起的死锁
  2. 快讯|腔镜手术机器人研发商“北京术锐”完成数千万元 A 轮融资,顺为资本领投...
  3. OpenCV计算机视觉实战(Python版)_002图像基本操作
  4. mysql 跨服务器 etl_mysql数据库跨服务器查询【需要确定mysql支持FEDERATED ,可以参照文章内容自己配置】...
  5. Unity编辑器控件的使用(—)
  6. docker跑codalab_Codalab使用与采坑
  7. android.jar 位置,Android 导入jar包 so模块--导入放置的目录
  8. Java J2SE 系列视频教程(北京上学堂马士兵老师经典java讲义)
  9. java digester map_Tomcat7启动分析(三)Digester的使用(转载)
  10. 解决树莓派开机黑屏不显示桌面问题
  11. 豆瓣超高评分《扫黑风暴》热评爬取可视化展示
  12. python stdin什么意思_python中stdin是什么
  13. 教你如何轻松测试局域网网速
  14. etc/hosts.allow和/etc/hosts.deny详解
  15. 【好物推荐】LICEcap – 灵活好用,GIF 屏幕录制工具
  16. 》古文诗词:庄子·杂篇·天下
  17. 陈力:传智播客古代 珍宝币 泡泡龙游戏开发第22讲:PHP语法、数据类型(整型、布尔型、浮点型、字符串型)
  18. 炼丹系列2: Stochastic Weight Averaging (SWA) Exponential Moving Average(EMA)
  19. WINPE U盘版制作-深山红叶版,完美者等
  20. 计算机毕业设计源代码java项目开发实例ssm+mysql实现简单的物流快递管理系统[包运行成功]

热门文章

  1. war部署到tomcat
  2. JavaScript全面学习(中阶)
  3. 【转贴】mysql导入数据load data infile用法
  4. AJAX+JavaScript无刷新检查用户名
  5. java 集合读写同步_JAVA多线程学习十六 - 同步集合类的应用
  6. illegal multibyte sequence python3
  7. JavaScript图片库
  8. Java中数据是如何存储
  9. lua工具库penlight--08额外的库(二)
  10. C#解析Markdown文档,实现替换图片链接操作