ASP.NET Core 中间件 自定义全局异常中间件以及 MVC异常过滤器作用
中间件是一种装配到应用管道以处理请求和响应的软件。 每个组件:
- 选择是否将请求传递到管道中的下一个组件。
- 可在管道中的下一个组件前后执行工作。
请求委托用于生成请求管道。 请求委托处理每个 HTTP 请求。
使用 RunMap 和 Use 扩展方法来配置请求委托。 可将一个单独的请求委托并行指定为匿名方法(称为并行中间件),或在可重用的类中对其进行定义。 这些可重用的类和并行匿名方法即为中间件,也叫中间件组件。 请求管道中的每个中间件组件负责调用管道中的下一个组件,或使管道短路。 当中间件短路时,它被称为“终端中间件”,因为它阻止中间件进一步处理请求。
将 HTTP 处理程序和模块迁移到 ASP.NET Core 中间件介绍了 ASP.NET Core 和 ASP.NET 4.x 中请求管道之间的差异,并提供了更多的中间件示例。
中间件顺序
向 Startup.Configure
方法添加中间件组件的顺序定义了针对请求调用这些组件的顺序,以及响应的相反顺序。 此顺序对于安全性、性能和功能至关重要。
- // 运行时调用此方法。使用此方法配置HTTP请求管道。
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- }
- // 启用swagger中间件
- app.UseSwaggerMiddleware();
- // 全局异常捕获
- app.UseErrorHandlingMiddleware();
- //静态文件
- app.UseUploadConfig();
- // 路由中间件
- app.UseRouting();
- // 跨域检查
- app.UseCors(_allowSpecificOrigins);
- // 启用多租户中间件(自定义)
- app.UseMultiTenant();
- // (认证中间件)启用Authentication中间件,遍历策略中的身份验证方案获取多张证件,最后合并放入HttpContext.User中
- app.UseAuthentication();
- // (授权中间件)对请求进行权限验证
- app.UseAuthorization();
- app.UseEndpoints(endpoints =>
- {
- endpoints.MapControllers();
- //endpoints.MapControllerRoute("default", "{__tenant__=tenant1}/api/{controller=Home}/{action=Index}/{id?}");
- //endpoints.MapControllerRoute("default", "{__tenant__=}/api/{controller=Home}/{action=Index}");
- });
- }
在上述代码中:
- 在使用单个用户帐户创建新的 Web 应用时未添加的中间件已被注释掉。
- 并非所有中间件都需要准确按照此顺序运行,但许多中间件必须遵循这个顺序。 例如:
UseCors
、UseAuthentication
和UseAuthorization
必须按照上述顺序运行。- 由于此错误,
UseCors
当前必须在UseResponseCaching
之前运行。
以下 Startup.Configure
方法将为常见应用方案添加中间件组件:
- 异常/错误处理
- 当应用在开发环境中运行时:
- 开发人员异常页中间件 (UseDeveloperExceptionPage) 报告应用运行时错误。
- 数据库错误页中间件报告数据库运行时错误。
- 当应用在生产环境中运行时:
- 异常处理程序中间件 (UseExceptionHandler) 捕获以下中间件中引发的异常。
- HTTP 严格传输安全协议 (HSTS) 中间件 (UseHsts) 添加
Strict-Transport-Security
标头。
- 当应用在开发环境中运行时:
- HTTPS 重定向中间件 (UseHttpsRedirection) 将 HTTP 请求重定向到 HTTPS。
- 静态文件中间件 (UseStaticFiles) 返回静态文件,并简化进一步请求处理。
- Cookie 策略中间件 (UseCookiePolicy) 使应用符合欧盟一般数据保护条例 (GDPR) 规定。
- 用于路由请求的路由中间件 (UseRouting)。
- 身份验证中间件 (UseAuthentication) 尝试对用户进行身份验证,然后才会允许用户访问安全资源。
- 用于授权用户访问安全资源的授权中间件 (UseAuthorization)。
- 会话中间件 (UseSession) 建立和维护会话状态。 如果应用使用会话状态,请在 Cookie 策略中间件之后和 MVC 中间件之前调用会话中间件。
- 用于将 Razor Pages 终结点添加到请求管道的终结点路由中间件(带有 MapRazorPages 的 UseEndpoints)。
内置中间件
ASP.NET Core 附带以下中间件组件。 “顺序”列提供备注,以说明中间件在请求处理管道中的放置,以及中间件可能会终止请求处理的条件。 如果中间件让请求处理管道短路,并阻止下游中间件进一步处理请求,它被称为“终端中间件”。 若要详细了解短路,请参阅使用 IApplicationBuilder 创建中间件管道部分。
自定义中间件 比如异常中间件
首先,创建一个中间件ExceptionMiddleware
- using Microsoft.AspNetCore.Http;
- using Microsoft.Extensions.Logging;
- using Newtonsoft.Json;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading.Tasks;
- namespace NetLock.Presentation.Api.Middleware
- {
- public class ErrorHandlingMiddleware
- {
- private readonly RequestDelegate next;
- private readonly ILogger<ErrorHandlingMiddleware> _logger;
- public ErrorHandlingMiddleware(RequestDelegate next, ILogger<ErrorHandlingMiddleware> logger)
- {
- this.next = next;
- this._logger = logger;
- }
- public async Task InvokeAsync(HttpContext context)
- {
- try
- {
- await next(context);
- }
- catch (Exception ex)
- {
- await HandleExceptionAsync(context, ex);
- }
- }
- private Task HandleExceptionAsync(HttpContext context, Exception ex)
- {
- //var code = HttpStatusCode.InternalServerError; // 500 if unexpected
- var code = StatusCodes.Status500InternalServerError;
- string info = "服务器内部错误,无法完成请求";
- if (ex is Exception)
- {
- code = 401;
- info = ex.Message == "" ? "未登录" : ex.Message;
- }
- else if (ex is UnAuthorizeException)
- {
- code = 401;
- info = ex.Message == "" ? "无权访问" : ex.Message;
- }
- else
- {
- switch (context.Response.StatusCode)
- {
- case 401:
- info = "没有权限";
- break;
- case 404:
- info = "未找到服务";
- break;
- case 403:
- info = "服务器理解请求客户端的请求,但是拒绝执行此请求";
- break;
- case 500:
- info = "服务器内部错误,无法完成请求";
- break;
- case 502:
- info = "请求错误";
- break;
- default:
- info = ex.Message;
- break;
- }
- }
- _logger.LogError(info); // todo:可记录日志,如通过注入Nlog等三方日志组件记录
- var result = JsonConvert.SerializeObject(new { Coede= code.ToString(), Message = info });
- context.Response.ContentType = "application/json";
- context.Response.StatusCode = code;
- return context.Response.WriteAsync(result);
- }
- }
- }
管道的添加顺序决定了它的执行顺序,所以如果您想扩大异常捕获的范围,可以将该管道放置在 Configure
的第一行。 但是!! 您会发现,这个默认的AspNet Core项目不是已经在第一行弄了一个异常处理么?
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- }
- else
- {
- app.UseExceptionHandler("/Error");
- }
这行代码大家在初始化新AspNetCore项目时就会看到,也有可能您只有上半段,这和模板有关系。不过这都没有关系,它的作用就是捕获和处理异常而已。关于 UseDeveloperExceptionPage
该扩展咱们就不多说了,它的意思是:对于开发模式,一旦报错就会跳转到错误堆栈页面。 而第二个 UseExceptionHandler
就很有意思了,从它命名就可以看出,它肯定是个错误拦截程序。那么它和咱们自定义的异常处理管道有什么区别呢?
“不指定肯定有个默认吧!” 是的,它就是默认的错误处理。所以,它其实也是一个中间件,它的真身叫做 ExceptionHandlerMiddleware
。在使用 UseExceptionHandler
方法时,我们可以选填各种参数。比如上方的代码,填入了 "/Error"
参数,表示当产生异常的时候,将定向到对应路径,此处就定位的是: “http://localhost:5001/Error” 。当然您也可以随意指定页面,比如 漂亮的乔殿下页面。
创建 HandleException(HttpContext context, Exception e) 处理异常,判断是 Development 环境下,输出详细的错误信息,非 Development 环境仅提示调用者“抱歉,出错了”,同样,在 Startup.cs 中将 ExceptionMiddleware 加入管道中
- //ExceptionMiddleware 加入管道
- app.UseMiddleware<ExceptionMiddleware>();
通过依赖注入和管道中间件两种不同的全局捕获异常处理。实际项目中,也是应当区分不同的业务场景,输出不同的日志信息,不管是从安全或者是用户体验友好性上面来说,都是非常值得推荐的方式,全局异常捕获处理,完全和业务剥离。
IExceptionFilter 作为MVC中间件之间的内容,它需要MVC在发现错误之后将错误信息提交给它处理,因此它的错误处理范围仅限于MVC中间件。所以,假如我们需要捕获MVC中间件之前的一些错误,其实是捕获不到的。 而对于ExceptionHandlerMiddleware
中间件来说就很简单了,它作为第一个中间件,凡是在它之后的所有错误它都能够捕获得到。
那么这么看来是否IExceptionFilter
就毫无用武之地了呢? 非也,假如您想在MVC发生异常时快速捕获和处理,使用过滤器其实是您不错得选择,如果您仅仅关心控制器之间的异常,那么过滤器也是很好的选择。
还记得刚开始我们在过滤器中说过的这一行代码吗:context.ExceptionHandled = true;
。如果在IExceptionFilter
中将异常标记为已经处理之后,则第一道异常处理中间件就认为没有错误了,不会进入到处理逻辑中。所以,如果咱们不把该属性改为 true
,很有可能出现拦截结果被覆盖的情况。
ASP.NET Core 中间件 自定义全局异常中间件以及 MVC异常过滤器作用的更多相关文章
- Asp.Net Core 第06局:中间件
总目录 前言 本文介绍Asp.Net Core 中间件. 环境 1.Visual Studio 2017 2.Asp.Net Core 2.2 开局 第一手:中间件概述 1.中间件:添加到应用 ...
- 如何在ASP.NET Core中自定义Azure Storage File Provider
文章标题:如何在ASP.NET Core中自定义Azure Storage File Provider 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p ...
- ASP.NET Core Identity自定义数据库结构和完全使用Dapper而非EntityFramework Core
前言 原本本节内容是不存在的,出于有几个人问到了我:我想使用ASP.NET Core Identity,但是我又不想使用默认生成的数据库表,想自定义一套,我想要使用ASP.NE Core Identi ...
- ASP.NET Core中,UseDeveloperExceptionPage扩展方法会吃掉异常
在ASP.NET Core中Startup类的Configure方法中,有一个扩展方法叫UseDeveloperExceptionPage,如下所示: // This method gets call ...
- 干货分享:ASP.NET CORE(C#)与Spring Boot MVC(JAVA)异曲同工的编程方式总结
目录 C# VS JAVA 基础语法类比篇: 一.匿名类 二.类型初始化 三.委托(方法引用) 四.Lambda表达式 五.泛型 六.自动释放 七.重写(override) ASP.NET CORE ...
- ASP.NET CORE(C#)与Spring Boot MVC(JAVA)
干货分享:ASP.NET CORE(C#)与Spring Boot MVC(JAVA)异曲同工的编程方式总结 目录 C# VS JAVA 基础语法类比篇: 一.匿名类 二.类型初始化 三.委托(方 ...
- 从ASP.Net Core Web Api模板中移除MVC Razor依赖项
前言 :本篇文章,我将会介绍如何在不包括MVC / Razor功能和包的情况下,添加最少的依赖项到ASP.NET Core Web API项目中. 一.MVC VS WebApi (1)在ASP. ...
- ASP.NET Core 中间件自定义全局异常处理
目录 背景 ASP.NET Core过滤器(Filter) ASP.NET Core 中间件(Middleware) 自定义全局异常处理 .Net Core中使用ExceptionFilter .Ne ...
- Asp.Net Core 通过自定义中间件防止图片盗链的实例(转)
一.原理 要实现防盗链,我们就必须先理解盗链的实现原理,提到防盗链的实现原理就不得不从HTTP协议说起,在HTTP协议中,有一个表头字段叫referer,采用URL的格式来表示从哪儿链接到当前的网页或 ...
随机推荐
- day2(RESTful风格API)
1.RESTful风格API 详情查看博客地址:https://www.cnblogs.com/xiaonq/p/10053234.html 1.1 什么是RESTful REST与技术无关,代表的 ...
- 第8.6节 Python类中的__new__方法深入剖析:调用父类__new__方法参数的困惑
上节<第8.5节 Python类中的__new__方法和构造方法__init__关系深入剖析:执行顺序及参数关系案例详解>通过案例详细分析了两个方法的执行顺序,不知大家是否注意到了,在上述 ...
- 第8.25节 Python风格的__getattribute__属性访问方法语法释义及使用
一. 引言 在<第8.13节 Python类中内置方法__repr__详解>老猿介绍了在命令行方式直接输入"对象"就可以调用repr内置函数或__repr__方法查看对 ...
- 第11.11节 Python正则表达式的指定重复次数匹配模式及元字符”{}”功能介绍
在<第11.8节 Pytho正则表达式的重复匹配模式及元字符"?". "". "+"功能介绍>和<第11.10节 Pyth ...
- PyQt(Python+Qt)学习随笔:QTreeView树形视图的wordWrap属性
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QTreeView树形视图的wordWrap属性用于控制视图展示数据项文本的单词换行原则,如果该值为 ...
- PyQt(Python+Qt)学习随笔:视图中类QAbstractItemView的dragDropOverwriteMode属性不能覆盖写的问题
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 在<PyQt(Python+Qt)学习随笔:视图中类QAbstractItemView的dra ...
- kettle如何从cube抽数据
接触kettle已经还是有一段时间了,但是一直都使用简单的输入.输出(二维数据库to二维数据库).今天,突然接到一个需求,需要从多维数据库(CUBE)里面将数据抽取到二维数据库,我难住了,不知道该如何 ...
- Python Flask后端异步处理(二)
在实际的应用场景中,如用户注册,用户输入了注册信息后,后端保存信息到数据库中,然后跳转至登录界面,这些操作用户需要等待的时间非常短,但是如果是有耗时任务,比如对输入的网址进行漏洞扫描,在后端处理就会花 ...
- Hive数据导入HBase引起数据膨胀引发的思考
最近朋友公司在做一些数据的迁移,主要是将一些Hive处理之后的热数据导入到HBase中,但是遇到了一个很奇怪的问题:同样的数据到了HBase中,所占空间竟增长了好几倍!详谈中,笔者建议朋友至少从几点原 ...
- ARC109F - 1D Kingdom Builder
一行格子,其中小于\(0\)的格子为白色,大于\(n\)的格子为黑色,中间的格子颜色由题目给出. 有一些格子需要被标记.标记按照以下规则进行:选择一个颜色\(c\),找到一个未标记的 旁边有标记点的 ...