900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > .net 怎么在控制器action中返回一个试图_ASP.NET Core MVC/WebAPI中另辟蹊径的全局

.net 怎么在控制器action中返回一个试图_ASP.NET Core MVC/WebAPI中另辟蹊径的全局

时间:2020-12-05 09:33:23

相关推荐

.net 怎么在控制器action中返回一个试图_ASP.NET Core MVC/WebAPI中另辟蹊径的全局

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

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

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

开始打码实现吧

为了方便演示,我先搭建一个基础的 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,其实这种在控制器中实现异常记录的方式个人感觉更简单且方便,既然微软已经为我们开放了这样的方式,我们为什么不用呢?

网站开源代码:

/ldqk/Masuit.MyBlogs​

转自原文:

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

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

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。