.Net Core 2.2 升级到 .Net Core 3.1

news2024/12/27 13:46:04

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

编译或发布代码分析器在控制台输出警告:
CSC : warning AD0001: Analyzer 'Microsoft.AspNetCore.Mvc.Analyzers.TopLevelParameterNameAnalyzer' threw an exception of type 'System.NullReferenceException' with message 'Object reference not set to an instance of an object.'.
原因是你的项目中,还残留.net core 2.2版本的组件,可以这样检查:

卸载再安装或直接升级最新的版本即可。

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)
                    {
                         //你的校验方式
                         //todo
                        context.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 => ……

也必须在app.UseRouting和app.UseEndpoints 之间。

文件下载
  单独封装的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);
context.Response.Body.FlushAsync();
这才顺利完成了更新。真的太坑了,不过也感觉微软的抽象化做得很好,按需引入,减少项目的冗余。

更多升级指南请参考:从 ASP.NET Core 2.2 迁移到 3.0 | Microsoft Learn

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

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

相关文章

基于Python的点赞、收藏博客

文章目录 前言一、点赞和取消点赞1.请求url和请求方法2.入参3.响应结果3.1点赞3.2取消点赞 4.代码5.效果 二、收藏2.1判断博客是否收藏过2.1.1请求url和请求方法2.1.2响应结果未收藏已收藏 2.1.3代码2.1.4效果 2.2收藏博客2.2.1请求url和请求方法2.2.2入参2.2.3响应结果2.2.4代…

爬虫小白应该如何学习爬虫

什么是Python3网络爬虫&#xff1f; 定义&#xff1a; 网络爬虫&#xff08;Web Spider&#xff09;&#xff0c;又被称为网页蜘蛛&#xff0c;是一种按照一定的规则&#xff0c;自动地抓取网站信息的程序或者脚本。爬虫其实是通过编写程序&#xff0c;模拟浏览器上网&#x…

高频面试题/面试经常被问到怎么处理接口依赖该怎么回答

前言 由于快到金九银十了&#xff0c;笔者最近呢发的都是一些有关面试方面的文章&#xff0c;有需要的小伙伴可以看看笔者的文章希望可以帮助到大家&#xff0c;今天呢笔者想和大家来聊聊在面试中被问到怎么处理接口依赖改怎么回答&#xff0c;废话就不多说了咱们直接进入主题…

互斥锁实现线程互斥(嵌入式学习)

互斥锁实现线程互斥 互斥锁的概念互斥锁的函数示例代码 互斥锁的概念 互斥锁&#xff08;Mutex&#xff09;是一种用于多线程编程的同步原语&#xff08;synchronization primitive&#xff09;&#xff0c;用于实现线程之间的互斥访问共享资源。互斥锁提供了一种机制&#xff…

限流式保护器在高校中的应用

安科瑞虞佳豪 4月10日下午1点50多分 浙大紫金港校区边一活动板房发生火情。起火位置为浙大紫金港校区的动物保护基地。 “起火的地方是有一个学生动物保护者协会&#xff0c;里面有一些学生救助的猫、狗等小动物。”一位学校的学生告诉潮新闻记者。 随后&#xff0c;潮新闻…

C语言(14) 谈谈嵌入式 C 语言踩内存问题!

1 概述 C 语言内存问题&#xff0c;难在于定位&#xff0c;定位到了就好解决了。 这篇笔记我们来聊聊踩内存。踩内存&#xff0c;通过字面理解即可。本来是操作这一块内存&#xff0c;因为设计失误操作到了相邻内存&#xff0c;篡改了相邻内存的数据。 踩内存&#xff0c;轻则…

Shopify股价在暴涨了78%以后,还值得投资吗?

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 今年以来Shopify (SHOP)的股价一直在上涨&#xff0c;迄今为止的涨幅已经超过了78%&#xff0c;并且远远跑赢了美股的所有主要指数。 猛兽财经认为&#xff0c;Shopify的股价之所以能在今年上涨&#xff0c;主要受到以下几…

windows2022证书配置.docx

Windows证书的配置 要求两台主机&#xff0c;一台作为域&#xff0c;一台进入域 按要求来选择角色服务 确认之后安装 安装完以后配置证书服务 选择服务 按要求配置 注&#xff1a;此处不用域用户登陆无法使用企业CA 按要求来 创建新的私钥 这几处检查无误后默认即可 有效期…

实验篇(7.2) 16. 站对站安全隧道 - 通过聚合隧道走对方上网(FortiGate-IPsec) ❀ 远程访问

【简介】前面所有实验基本上是由向导来完成的&#xff0c;只有隧道聚合实验是手动设置的。那么远程访问经常用到的走对方宽带上网功能&#xff0c;需要怎样手动配置呢&#xff1f; 实验要求与环境 OldMei集团深圳总部防火墙现在有三条宽带了&#xff0c;二条普通宽带用来上网及…

SSCMS 内容管理系统介绍

概述 SSCMS 内容管理系统基于微软 .NET Core 平台开发,用于创建在 Windows、Linux、Mac 以及 Docker 上运行的 Web 应用程序和服务。 SSCMS 针对企业级客户开发,完全开源免费,可以用于商业用途不需要支付任何产品或授权费用。 SSCMS 经受了时间考验,1.0 版本在2003年发布…

跨模态检索最新高质量综述《Image-text Retrieval: A Survey on Recent Research and Development》

Image-text Retrieval: A Survey on Recent Research and Development 图像文本检索研究进展综述 2022.03 本文已把文献的引用逐个换成相应的论文标题&#xff0c;方便查找和阅读 摘要 本文从四个方面对ITR方法进行了全面和最新的调查。通过将ITR系统剖析为两个过程&#xff1…

基于Java+Swing+Mysql实现汽车信息管理系统

基于JavaSwingMysql实现汽车信息管理系统 一、系统介绍二、功能展示1.登陆2.车辆信息3.车辆入库4.车辆出库5.车辆查询6、车辆信息修改 三、数据库四、其它1.其他系统实现五.获取源码 一、系统介绍 系统实现汽车入库&#xff0c;汽车出库&#xff0c;汽车查询&#xff0c;汽车信…

2023软件测试八股文最全文档,再也不用担心面试了

前言 6月份已经快过完一半了&#xff0c;马上就要到金九银十的黄金招聘季节了&#xff0c;还在准备面试跳槽涨薪的小伙伴们可以看看本篇文章哟&#xff0c;这里呢笔者就不多说废话了直接上干货&#xff01;答案已整理好&#xff0c;文末拿去即可&#xff01;非常好用&#xff…

day57_Git

今日内容 零、 复习昨日 零、 复习昨日 文章目录 零、 复习昨日一、引言二、介绍三、Git安装3.1 下载Git3.2 安装3.3 基本配置3.4 测试 四、架构五、仓库5.1 新建仓库5.2 工作区5.3 暂存区5.4 分支 六、基本操作6.1 查看仓库状态6.2 暂存文件6.3 提交文件6.4 撤销已经add的文件…

POSTGRESQL PG_GATHER 如何单纯用SQL 就可以产生一个有意思的PG 的分析报告

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

【Android开发基础】Canvas画笔(以刮刮乐为例)

文章目录 一、引言二、设计1、获取图片资源2、获取屏幕信息3、Canvas涂层4、随机内容5、屏幕监听 三、附件1、UI设计2、总代码&#xff08;1&#xff09;控件初始化&#xff08;2&#xff09;图层初始化 3、源代码 一、引言 &#xff08;本篇博客只说明Canvas画笔的使用&#…

STM32单片机(六)TIM定时器 -> 第六节:TIM输入捕获练习(输入捕获模式测频率和PWMI模式测频率占空比)

❤️ 专栏简介&#xff1a;本专栏记录了从零学习单片机的过程&#xff0c;其中包括51单片机和STM32单片机两部分&#xff1b;建议先学习51单片机&#xff0c;其是STM32等高级单片机的基础&#xff1b;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 &#xff1a;适用于想要…

docker inspect

docker inspect 命令用于获取有关 Docker 容器、镜像、网络等的详细信息。它提供了关于指定对象的元数据和配置的完整视图&#xff0c;包括运行状态、网络设置、卷挂载、环境变量等。 以下是一些常见的字段和属性&#xff0c;可以根据需要选择其中一些或全部列出&#xff1a; …

【算法与数据结构】202、LeetCode快乐数

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;先用一个dowhile循环计算整数各个位数字的平方和&#xff0c;然后在unordered_set里面插入n&#xff0…

C语言学习笔记:函数

✨博文作者&#xff1a;烟雨孤舟 &#x1f496; 喜欢的可以 点赞 收藏 关注哦~~ ✍️ 作者简介: 一个热爱大数据的学习者 ✍️ 笔记简介&#xff1a;作为大数据爱好者&#xff0c;以下是个人总结的学习笔记&#xff0c;如有错误&#xff0c;请多多指教&#xff01; 目录 简介 …