.Net Core 2.2升級(jí)3.1的避坑指南(小結(jié))
寫在前面
微軟在更新.Net Core版本的時(shí)候,動(dòng)作往往很大,使得每次更新版本的時(shí)候都得小心翼翼,坑實(shí)在是太多。往往是悄咪咪的移除了某項(xiàng)功能或者組件,或者不在支持XX方法,這就很花時(shí)間去找回需要的東西了,下面是個(gè)人在遷移.Net Core WebApi項(xiàng)目過程中遇到的問題匯總:
開始遷移
1. 修改*.csproj項(xiàng)目文件
<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之后已被標(biāo)記棄用。
路由配置:
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?}"); });
你以為結(jié)束了?還沒。
坑
這時(shí)候你以為結(jié)束了,興高采烈的去服務(wù)器裝好runningTime和hosting相應(yīng)的版本,運(yùn)行……
HTTP Error 500.30 – ANCM In-Process Start Failure
直接cmd,進(jìn)入到發(fā)布目錄,執(zhí)行:
E:\你的路徑>dotnet xxx.dll
顯示詳細(xì)錯(cuò)誤
而我的相應(yīng)250代碼行是:
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
搜索最新的AutoMapper根本沒更新或改變,所以不是這個(gè)組件的問題。
嘗試下載補(bǔ)丁Windows6.1-KB974405-x64.msu,無果……
卸載sdk重置,無果……
修改web.config,無果……
修改應(yīng)用池32位,無果……
最后,查看發(fā)布:勾選上【刪除現(xiàn)有文件】,解決……
Endpoint contains CORS metadata, but a middleware was not found that supports CORS.
順利可以啟動(dòng)項(xiàng)目之后,發(fā)現(xiàn)有些接口:
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 的時(shí)候
app.UseCors();
不是需要強(qiáng)制在指定位置的,在3.0之后需要設(shè)置在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……
運(yùn)行之后,有些接口沒有數(shù)據(jù)返回,而有些直接報(bào)錯(cuò)了。原因又是爸爸把Newtonsoft.Json移除,使用內(nèi)置的System.Text.Json,所以依賴于Newtonsoft.Json的組件將不可用,那么,只能手動(dòng)添加。
Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson -Version 3.1.5
然后添加引用
public void ConfigureServices(IServiceCollection services) { services.AddControllers().AddNewtonsoftJson(); }
目前還不太建議你使用內(nèi)置的序列化,因?yàn)閷?shí)在太多功能或方法不支持,詳細(xì)對(duì)比請(qǐng)參考https://docs.microsoft.com/zh-cn/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to
授權(quán)相關(guān)
基于策略授權(quán),我想在座的加班狗都是大同小異,在2.2以前:
public class PolicyHandler : AuthorizationHandler<PolicyRequirement> { /// <summary> /// 授權(quán)方式(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> /// 授權(quán)處理 /// </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; //獲取授權(quán)方式 var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync(); if (defaultAuthenticate != null) { //驗(yàn)證簽發(fā)的用戶信息 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) { //你的校驗(yàn)方式 //todo context.Succeed(requirement); } else { HandleBlocked(context, requirement); } return; } } HandleBlocked(context, requirement); } /// <summary> /// 驗(yàn)證失敗返回 /// </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 }; //不要調(diào)用 context.Fail(),設(shè)置為403會(huì)顯示不了自定義信息,改為Accepted202,由客戶端處理,; context.Succeed(requirement); } }
然后發(fā)現(xiàn)升級(jí)到3.0之后,
var httpContext = (context.Resource as AuthorizationFilterContext).HttpContext;
3.0不再支持返回AuthorizationFilterContext,而是返回的是RouteEndpoint,這句代碼就會(huì)報(bào)錯(cuò),所以修改的方式就是注入IHttpContextAccessor,從里面獲取HttpContext,這里就不用演示了吧。
并修改PolicyHandler校驗(yàn)失敗時(shí)候調(diào)用的方法:
/// <summary> /// 驗(yàn)證失敗返回 /// </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, //允許的服務(wù)器時(shí)間偏差的偏移量 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"; //無授權(quán)返回自定義信息 context.Response.WriteAsync(JsonConvert.SerializeObject(new UnAuthorizativeResponse())); return Task.CompletedTask; } }; });
UnAuthorizativeResponse 是自定義返回的內(nèi)容。
Startup.Configure中啟用Authentication,注意順序
app.UseRouting(); //跨域 app.UseCors(one); app.UseCors(two); …… //啟用 Authentication app.UseAuthorization(); app.UseAuthentication(); app.UseEndpoints(endpoints => ……
也必須在app.UseRouting和app.UseEndpoints之間。
文件下載
單獨(dú)封裝的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開始循環(huán)讀取要下載文件的內(nèi)容 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字節(jié))大小的內(nèi)容到服務(wù)器內(nèi)存中 int currentRead = fs.Read(buffer, 0, bufferSize); context.Response.Body.Write(buffer, 0, currentRead); context.Response.Body.Flush(); hasRead += currentRead; } } } }
下載的時(shí)候發(fā)現(xiàn)以下錯(cuò)誤: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 ……
意思不運(yùn)行同步操作,修改為
context.Response.Body.WriteAsync(buffer, 0, currentRead);
這才順利完成了更新。真的太坑了,不過也感覺微軟的抽象化做得很好,按需引入,減少項(xiàng)目的冗余。
更多升級(jí)指南請(qǐng)參考“孫子兵法”:https://docs.microsoft.com/zh-cn/aspnet/core/migration/22-to-30?view=aspnetcore-2.1&tabs=visual-studio
作者:EminemJK(山治先生)
出處:https://www.cnblogs.com/EminemJK/
到此這篇關(guān)于.Net Core 2.2升級(jí)3.1的避坑指南(小結(jié))的文章就介紹到這了,更多相關(guān).Net Core 2.2升級(jí)3.1內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
.NET Core系列之MemoryCache 緩存選項(xiàng)
這篇文章主要介紹了.NET Core系列之MemoryCache 緩存選項(xiàng),詳細(xì)的介紹一下 MSCache 中的 Options,由此來介紹一些 MSCache 中的內(nèi)部機(jī)制,感興趣的小伙伴們可以參考一下2018-08-08asp.net中Fine Uploader文件上傳組件使用介紹
最近在處理后臺(tái)數(shù)據(jù)時(shí)需要實(shí)現(xiàn)文件上傳.考慮到對(duì)瀏覽器適配上采用Fine Uploader. Fine Uploader 采用ajax方式實(shí)現(xiàn)對(duì)文件上傳.同時(shí)在瀏覽器中直接支持文件拖拽[對(duì)瀏覽器版本有要求類似IE版本必須是9或是更高的IE10].2013-01-01.NET/C#利用反射調(diào)用含ref或out參數(shù)的方法示例代碼
這篇文章主要給大家介紹了關(guān)于.NET/C#利用反射調(diào)用含ref或out參數(shù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09.NET core 3.0如何使用Jwt保護(hù)api詳解
這篇文章主要給大家介紹了關(guān)于.NET core 3.0如何使用Jwt保護(hù)api的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用.NET core 3.0具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11一個(gè)簡(jiǎn)單的asp.net 單點(diǎn)登錄實(shí)現(xiàn)
上次做了學(xué)校的火車訂票系統(tǒng),那邊要求要從學(xué)生信息平臺(tái)直接點(diǎn)過來就是登錄狀態(tài),不用在重新登錄。學(xué)生信息平臺(tái)原來是用asp做的,而火車訂票系統(tǒng)是asp.net做的。兩個(gè)網(wǎng)站的學(xué)生信息調(diào)用的是同一個(gè)數(shù)據(jù)庫。2009-11-11asp.net(C#)生成Code39條形碼實(shí)例 條碼槍可以掃描出
這篇文章主要介紹了asp.net(C#)生成Code39條形碼實(shí)例 條碼槍可以掃描出。需要的朋友可以過來參考下,希望對(duì)大家有所幫助2014-02-02Linq to SQL Delete時(shí)遇到問題的解決方法
在Linq to SQL中要?jiǎng)h除一行記錄,官方的例子教我這樣做2008-03-03Asp.Net FckEditor在web.config中配置的具體實(shí)例
Asp.Net FckEditor在web.config中配置的具體實(shí)例,需要的朋友可以參考一下2013-06-06