.Net Core 2.2升级3.1的避坑指南
寫(xiě)在前面
微軟在更新.Net Core版本的時(shí)候,動(dòng)作往往很大,使得每次更新版本的時(shí)候都得小心翼翼,坑實(shí)在是太多。往往是悄咪咪的移除了某項(xiàng)功能或者組件,或者不在支持XX方法,這就很花時(shí)間去找回需要的東西了,下面是個(gè)人在遷移.Net Core WebApi項(xiàng)目過(guò)程中遇到的問(wèn)題匯總:
開(kāi)始遷移
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é)束了?還沒(méi)。
坑
這時(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()); //原文地址:https://www.cnblogs.com/EminemJK/p/13206747.html搜索最新的AutoMapper根本沒(méi)更新或改變,所以不是這個(gè)組件的問(wèn)題。
嘗試下載補(bǔ)丁Windows6.1-KB974405-x64.msu?,無(wú)果……
卸載sdk重置,無(wú)果……
修改web.config,無(wú)果……
修改應(yīng)用池32位,無(wú)果……
最后,查看發(fā)布:勾選上【刪除現(xiàn)有文件】,解決……
Endpoint contains CORS metadata, but a middleware was not found that supports CORS.
順利可以啟動(dòng)項(xiàng)目之后,發(fā)現(xiàn)有些接口:
提示很明顯,在.net core 2.2 的時(shí)候不是需要強(qiáng)制在指定位置的,
app.UseCors();在3.0之后需要設(shè)置在app.UseRouting和app.UseEndpoints 之間:
The JSON value could not be converted to System.Int32. Path……
運(yùn)行之后,有些接口沒(méi)有數(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;//判斷是否過(guò)期var expirationTime = DateTime.Parse(httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration).Value);if (expirationTime >= DateTime.UtcNow){//你的校驗(yàn)方式//todocontext.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 過(guò)期 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";//無(wú)授權(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 => ……文件下載
單獨(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開(kāi)始循環(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);這才順利完成了更新。真的太坑了,不過(guò)也感覺(jué)微軟的抽象化做得很好,按需引入,減少項(xiàng)目的冗余。
更多升級(jí)指南請(qǐng)參考“孫子兵法”:
https://docs.microsoft.com/zh-cn/aspnet/core/migration/22-to-30?view=aspnetcore-2.1&tabs=visual-studio
總結(jié)
以上是生活随笔為你收集整理的.Net Core 2.2升级3.1的避坑指南的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 更优雅的在 Xunit 中使用依赖注入
- 下一篇: Asp.Net Core Blazor之