作为一名合格的.NET开发者,大家都知道在程序发生异常的时候,不应该将详细的异常堆栈信息抛给前台用户显示,我们应该对程序所有的不可预知的异常做统一处理,返回一个有好的提示给前台用户,并在程序里将错误信息以日志的形式记录下来,比如一个友好的错误页面,像我自己网站的404页面和503页面:

相信大家对统一异常处理都比较熟悉,可以通过自己实现一个异常拦截的中间件实现,也可以实现一个FilterAttribute对所有的控制器进行异常拦截,这都是比较常见的异常处理方式,但以上两种,如果想在程序出现错误时,不发生路由跳转直达错误页,有时候还是不太方便,所以,今天给大家另辟蹊径分享一个全局异常的同一拦截处理方式,发生错误时,页面路由不会发生跳转。

那就是微软自己提供的——UseExceptionHandler中间件。

开始打码实现吧

为了方便演示,我先搭建一个基础的http://ASP.NET Core项目,并创建了一个HomeController:

    public class HomeController : Controller{// GETpublic IActionResult Index(){return Ok("这是首页");}[HttpGet("test")]public ActionResult Test(){throw new Exception("手动发生一个异常");}}

再创建一个ErrorController控制器,并写一个Action来作为我们的错误页面:

    [Route("error")]public class ErrorController : Controller{[HttpGet]public IActionResult Index(){return Ok("假装是一个错误页面");}}

接下来实现异常处理中间件,该中间件在Startup的Configure方法中注册,需要传入一个路由,而错误页的路由是“/error”,所以注册中间件:

app.UseExceptionHandler("/error");

然后我们运行项目,触发一次异常:

发生异常的时候,确实已经到我们的错误页了,而且路由没有改变,但是,我们没有记录下发生错误时的堆栈信息,为了后期的诊断,我们肯定要记录详细的异常信息才行,那如何将异常信息记录下来呢?

UseExceptionHandler中间件中拦截到异常时,会将异常信息保存在请求上下文中,所以我们可以从HttpContext中拿到ExceptionHandler的异常信息:

var feature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();

如果程序有异常,那么feature是一个不为null的对象,其属性Error便是我们需要的Exception,所以,我们改造一下刚才的ErrorController:

    [Route("error")]public class ErrorController : Controller{[HttpGet]public IActionResult Index(){var feature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();if (feature != null){var exception = feature.Error;// todo:调用日志组件记录异常信息,或对异常做多路判断}return Ok("假装是一个错误页面");}}

比如本站的异常多路处理源码如下:

        [Route("ServiceUnavailable")]public ActionResult ServiceUnavailable(){var feature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();if (feature != null){string err;var req = HttpContext.Request;var ip = HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();switch (feature.Error){case DbUpdateConcurrencyException ex:err = $"异常源:{ex.Source},异常类型:{ex.GetType().Name},n请求路径:{req.Scheme}://{req.Host}{HttpUtility.UrlDecode(req.Path)},客户端用户代理:{req.Headers["User-Agent"]},客户端IP:{ip}t{ex.InnerException?.Message}t";LogManager.Error(err, ex);break;case DbUpdateException ex:err = $"异常源:{ex.Source},异常类型:{ex.GetType().Name},n请求路径:{req.Scheme}://{req.Host}{HttpUtility.UrlDecode(req.Path)},客户端用户代理:{req.Headers["User-Agent"]},客户端IP:{ip}t{ex?.InnerException?.Message}t";LogManager.Error(err, ex);break;case AggregateException ex:LogManager.Debug("↓↓↓" + ex.Message + "↓↓↓");ex.Handle(e =>{LogManager.Error($"异常源:{e.Source},异常类型:{e.GetType().Name},n请求路径:{req.Scheme}://{req.Host}{HttpUtility.UrlDecode(req.Path)},客户端用户代理:{req.Headers["User-Agent"]},客户端IP:{ip}t", e);return true;});break;case NotFoundException ex:Response.StatusCode = 404;return Request.Method.ToLower().Equals("get") ? (ActionResult)View("Index") : Json(new{StatusCode = 404,Success = false,ex.Message});default:LogManager.Error($"异常源:{feature.Error.Source},异常类型:{feature.Error.GetType().Name},n请求路径:{req.Scheme}://{req.Host}{HttpUtility.UrlDecode(req.Path)},客户端用户代理:{req.Headers["User-Agent"]},客户端IP:{ip}t", feature.Error);break;}}Response.StatusCode = 503;if (Request.Method.ToLower().Equals("get")){return View();}return Json(new{StatusCode = 503,Success = false,Message = "服务器发生错误!"});}

至此,全局异常处理已经完整实现。

总结

相较于自己实现中间件和FilterAttribute,其实这种在控制器中实现异常记录的方式个人感觉更简单且方便,既然微软已经为我们开放了这样的方式,我们为什么不用呢?

网站开源代码:

https://github.com/ldqk/Masuit.MyBlogs​github.com

转自原文:

ASP.NET Core MVC/WebAPI中另辟蹊径的全局统一异常处理方式​masuit.com

.net 怎么在控制器action中返回一个试图_ASP.NET Core MVC/WebAPI中另辟蹊径的全局统一异常处理方式...相关推荐

  1. .net 怎么在控制器action中返回一个试图_一个view事件分发,面试官6连问直击灵魂,我被虐的体无完肤...

    注:原文来自掘金作者xiangcman 写这篇文章其实是有原因的,说实话这次面试真的很失败,看着身边的人都拿到了高薪的工资,感觉自己还是有些惭愧.也更说明自己在很多方面的知识点还是不够扎实,于是再一次 ...

  2. mysql desc 显示备注_MySQL_Mysql中返回一个数据库的所有表名,列名数据类型备注,desc 表名; show columns from 表名; d - phpStudy...

    Mysql中返回一个数据库的所有表名,列名数据类型备注 desc 表名; show columns from 表名; describe 表名; show create table 表名; use in ...

  3. Pandas中xs()函数索引复合索引数据的不同切面数据(索引复合索引中需要的数据):索引列复合索引中的一个切面、索引行复合索引中的一个切面

    Pandas中xs()函数索引复合索引数据的不同切面数据(索引复合索引中需要的数据):索引列复合索引中的一个切面.索引行复合索引中的一个切面 目录

  4. Spring中Controller层、Filter层、Interceptor层全局统一异常处理

    Controller层.Filter层.Interceptor层全局统一异常处理 SpringBoot为异常处理提供了很多优秀的方法,但是像我这种新手在处理异常时还是会觉得一头包,终于我痛定思痛,总结 ...

  5. C 如何在函数中返回一个数组

    int test(int *b) {int source[5]={[1]=2,[3]=4,[4]=-2}; memcpy(b,source,5*sizeof(int));return 0; }int ...

  6. 在qt中用c语言数组,在QT函数中返回一个数组/把一个数组传参给函数

    1.把数组传参给函数 可以定义一个QVector的一个数组 QVector num(10); for(int  i =0;i<10;i++) num [i] = i*i; fun(num); / ...

  7. 如何在 ASP.NET Core MVC 5 中处理未知的 Action

    ASP.NET Core MVC 5 是一个轻量级,开源的,利于单元测试的基于 ASP.NET Core 运行时的 web 框架,在开发时你肯定会遇到不少那些 request 无法匹配 Action ...

  8. python链表中删除一个节点数据_python实现单链表中删除倒数第K个节点的方法

    本文实例为大家分享了python实现单链表中删除倒数第K个节点的具体代码,供大家参考,具体内容如下 题目: 给定一个链表,删除其中倒数第k个节点. 代码: class LinkedListAlgori ...

  9. 在https上面使用ws不加密_ASP.NET Core 3.1 中使用JWT认证

    转自:小伟06cnblogs.com/liuww/p/12177272.html JWT认证简单介绍 关于Jwt的介绍网上很多,此处不在赘述,我们主要看看jwt的结构. JWT主要由三部分组成,如下: ...

  10. java中的 请求体_在spring mvc test中访问请求体和请求头

    我创建了一个spring boot应用程序,这就是我的控制器的样子 . 我使用postman在请求体中发送json,在请求头中发送一个字符串,然后进一步散列json并将其与请求头获取的字符串进行比较 ...

最新文章

  1. LVS的DR工作模型解析
  2. 蓝桥杯-打印十字图-java
  3. VTK:可视化之Cursor3D
  4. poj 3460 bookstore
  5. C语言中extern修饰符的用法
  6. Android 获取设备ID,手机厂商,运营商,联网方式,获取系统语言,获取时区
  7. Oracle client 安装、配置
  8. (转)VS.NET使用
  9. javascript textContent与innerText的异同分析
  10. ubuntu 11.10下载和编译Android源码
  11. 订餐系统项目中OrderForm、OrderDTO、OrderMaster和ResultVO的区别
  12. python中dtype什么意思_浅谈python 中的 type(), dtype(), astype()的区别
  13. Java对二维数组排序
  14. 笔记本 续航测试软件,续航测试:较高强度运行状态_笔记本评测-中关村在线
  15. 2021年上半年软件设计师上午真题及答案解析
  16. web前端开发面试题(七)
  17. Java处理富文本编辑器的图片转为base64编码
  18. 如果诸葛亮用C#写出师表...
  19. PSTN与VoIP相关知识
  20. Mysql 中的 mvcc原理

热门文章

  1. 深入理解@Lazy注解
  2. 云服务器CentOS7上安装Mysql,并使用Navicat连接的最简便快速方法
  3. Spring Cloud Alibaba Sentinel之持久化篇
  4. 并发编程学习之Callable接口
  5. 到底什么才是自动化巡检?
  6. Linux系统Bash(Shell)基础知识(4)
  7. 渐进式加载 - 基础讲解
  8. laravel 社会化(联合)登录扩展包(QQ、微信、微博等)
  9. Poj(1274),二分图匹配
  10. 如何使用MIME类型