.Net Core 2.2升级3.1的避坑指南

写在前面

微软在更新.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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/308753.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[SpringSecurity]web权限方案_用户认证_自定义用户登录页面

在配置类中实现相关的配置 Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin() //自定义自己编写的登陆页面.loginPage("/login.html") //登陆页面设置.loginProcessingUrl("/user/login") //登陆访问路径.defa…

Asp.Net Core Blazor之容器部署

写在前面Docker作为开源的应用容器引擎&#xff0c;可以让我们很轻松的构建一个轻量级、易移植的容器&#xff0c;通过Docker方式进行持续交付、测试和部署&#xff0c;都是极为方便的&#xff0c;并且对于我们开发来说&#xff0c;最直观的优点还是解决了日常开发中的环境配置…

[SpringSecurity]web权限方案_用户授权_基于权限访问控制_基于角色访问控制_hasAuthority和hasAnyAuthority_hasRole和hasAnyRole

基于角色或权限进行访问控制 hasAuthority 方法 如果当前的主体具有指定的权限&#xff0c;则返回 true,否则返回 false 在配置类设置当前访问地址有哪些 Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin() //自定义自己编写的登…

.Net Core WebAPI + Axios +Vue 实现下载与下载进度条

写在前面老板说&#xff1a;系统很慢&#xff0c;下载半个小时无法下载&#xff0c;是否考虑先压缩再给用户下载&#xff1f;本来是已经压缩过了&#xff0c;不过第一反应应该是用户下的数量多&#xff0c;导致压缩包很大&#xff0c;然后自己测试发现&#xff0c;只是等待的时…

[SpringSecurity]web权限方案_用户授权_自定义403页面

自定义403页面 unauth.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body><h1>没有访问权限</h1></body> </html>配置类…

三分钟Docker-环境搭建篇

如题目显示&#xff0c;三分钟让你学会在windows上安装docker环境&#xff0c;开启docker之旅的第一步。安装前要求Windows 10 64位&#xff1a;专业版&#xff0c;企业版或教育版&#xff08;内部版本16299或更高版本&#xff09;。必须启用Hyper-V控制面板->程序和功能-&g…

[SpringSecurity]web权限方案_用户注销

用户注销 在配置类中添加退出映射地址 //退出http.logout().logoutUrl("/logout").logoutSuccessUrl("/test/hello").permitAll();测试 修改配置类&#xff0c;登陆成功之后跳转到成功页面 在成功页面添加超链接&#xff0c;写设置退出路径 success.htm…

骚年快答 | 为何微服务项目都使用单体代码仓库?

【答疑解惑】| 作者 / Edison Zhou这是恰童鞋骚年的第265篇原创内容之前在学习微软的示例eShopOnContainers时发现它使用的是单体代码仓库库&#xff0c;之后又发现大家在进行微服务项目开发时也都在使用单体代码仓库。问题来了&#xff0c;为啥要微服务项目都要使用单体仓库&a…

[SpringSecurity]web权限方案_自动登陆_原理分析和具体实现

自动登陆 1.cookie技术 2.安全框架机制实现自动登陆 这里我们使用安全框架机制实现自动登陆技术 实现原理 具体实现 第一步 创建数据库 CREATE TABLE persistent_logins (username varchar(64) NOT NULL,series varchar(64) NOT NULL,token varchar(64) NOT NULL,last_us…

[SpringSecurity]web权限方案_CSRF功能

CSRF CSRF功能默认是已经打开了&#xff01; 具体过程可以阅读CsrfFilter这个过滤器的源码 CSRF 理解 在登录页面添加一个隐藏域 <input type"hidden"th:if"${_csrf}!null"th:value"${_csrf.token}"name"_csrf "/>关闭安全…

[SpringSecurity]web权限方案_用户授权_注解使用

注解使用 Secured 判断用户是否具有角色&#xff0c;可以访问方法&#xff0c;另外需要注意的是这里匹配的字符串需要添加前缀“ROLE_“。 使用注解先要开启注解功能&#xff01; 启动类(配置类)开启注解 EnableGlobalMethodSecurity(securedEnable true) 在controller的…

我和ABP vNext 的故事

Abp VNext是Abp的.NET Core 版本&#xff0c;但它不仅仅只是代码重写了。Abp团队在过去多年社区和商业版本的反馈上做了很多的改进。包括性能、底层的框架设计&#xff0c;它融合了更多优雅的设计实践。不管你是自己需要快速上手项目、或者是公司的研发团队没有足够的能力去完整…

微软为 Visual Studio 推出新的 Razor 编辑器

随着 Visual Studio 最新版本的发布&#xff0c;微软推出了一款新的 Razor 编辑器&#xff0c;用于使用 MVC、Razor Pages 和 Blazor 进行本地开发。该工具目前还处于实验状态。Razor 是一种基于 HTML 和 C# 的模板语言&#xff0c;可以用来为 .NET Web 应用程序创建动态内容。…

禁用了云服务器的网卡怎么办?

点击上方关注“汪宇杰博客” ^_^导语我们平时管理云服务器时&#xff0c;难免误操作把网卡给禁用了&#xff0c;于是再也无法远程连接了。这时候怎么办呢&#xff1f;如果有虚拟机快照&#xff0c;能够恢复到上一个良好的时刻&#xff0c;但通常会损失这个时间段内的数据和应用…

[SpringBoot2]@MatrixVariableUrlPathHelper

场景 页面开发&#xff0c;cookie禁用了&#xff0c;session里面的内容怎么使用&#xff1a; session.set(a,b)—>jessionid—>cookie—>每次发请求携带 此时cookie禁用了&#xff0c;我们要怎么得到session里面的内容呢&#xff1f; url重写&#xff1a;/abc;jse…

WebBenchmark之动态数据测试

对于很多WebApi管理工具来说&#xff0c;针对接口的性能测试都拿固定的数据进行一个循环式的测试&#xff1b;这种测试只能确保当前数据下的有效性&#xff0c;但在性能测试中往往需要压测不同的数据分布&#xff0c;这样能够更准确地反映在不同数据下系统的处理能力。WebBench…

[SpringBoot2]Thymeleaf

引入starter <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>自动配置好了thymeleaf Configuration(proxyBeanMethods false) EnableConfigurationPrope…

【Ids4实战】分模块保护资源API

(毕竟西湖六月中)书接上文&#xff0c;上回书咱们说到了IdentityServer4&#xff08;下文统称Ids4&#xff09;官方已经从v3更新升级到了v4版本&#xff0c;我的Blog.Idp项目也做了同步更新&#xff0c;主要是针对快速启动UI做的对应修改&#xff0c;毕竟Ids4类库nuget包更新就…

[SpringBoot2]拦截器

拦截器 1.编写一个拦截器实现HandlerInterceptor接口2.拦截器注册到容器中(实现WebMvcConfigurer的addInterceptors)3.指定拦截规则[如果是拦截所有&#xff0c;静态资源也会被拦截] 1、HandlerInterceptor 接口 /*** 登录检查* 1、配置好拦截器要拦截哪些请求* 2、把这些配…

数据结构与算法专题——第九题 鸡尾酒排序

这篇我们来聊一下鸡尾酒排序&#xff0c;为了知道为啥取名为鸡尾酒&#xff0c;特意看了下百科&#xff0c;见框框的话&#xff0c;也只能勉强这么说了。要是文艺点的话&#xff0c;可以说是搅拌排序&#xff0c;通俗易懂点的话&#xff0c;就叫“双向冒泡排序”&#xff0c;我…