官方建议用app.UseExceptionHandler("/error")来集中处理异常,本例是一个具体的应用。
比如项目中有一个viewmodel,要求Name最大长度为5
/// <summary> /// 用户模型 /// </summary> public class usermodel { /// <summary> /// ID /// </summary> public int ID { get; set; } /// <summary> ///名称 /// </summary> [MaxLength(5, ErrorMessage = "长度不能超过5")] public string Name { get; set; } }
在TestController中有两个Action,都有异常的机率,Get方法中,一个异常是系统内置的0被整除,另一个是我们自定义的业务层级异常(.NET架构小技巧(8)中有涉及);AddUser是有Model验证有可能Name超过5个字符后报异常。Error方法一个错误处理Action,根据上下文的异常来分流系统内置异常,还是自定业务异常。
/// <summary> /// get接口 /// </summary> /// <returns></returns> [HttpGet] public IActionResult Get() { var ran = new Random(); switch (ran.Next(1, 4)) { case 1: int i = 0; var j = 10 / i; return Ok(); case 2: throw new RegisteredException("这是一个错误"); default: return Ok(); } } /// <summary> /// 添加用户接口 /// </summary> /// <param name="user"></param> /// <returns></returns> [HttpPost("/adduser")] public IActionResult AddUser([FromBody] usermodel user) { return Ok(user); } /// <summary> /// 错误处理页 /// </summary> /// <returns></returns> [HttpGet("/error")] public IActionResult Error() { var context = HttpContext.Features.Get<IExceptionHandlerFeature>(); //如果是业务自定义异常,进行特殊处理 if (context.Error is dameiException) { return Problem(detail: context.Error.StackTrace, title: $"{context.Error.Message}", type: "HIS"); } else { return Problem(detail: context.Error.StackTrace, title: context.Error.Message); } }
层级异常类
using System; namespace WebApiError { /// <summary> /// 产品异常 /// </summary> public class dameiException : ApplicationException { /// <summary> /// /// </summary> /// <param name="message"></param> public dameiException(string message) : base(message) { } } /// <summary> /// His项目异常 /// </summary> public class HisException : dameiException { /// <summary> /// /// </summary> /// <param name="message"></param> public HisException(string message) : base(message) { } } /// <summary> /// Lis项目异常 /// </summary> public class LisException : dameiException { /// <summary> /// /// </summary> /// <param name="message"></param> public LisException(string message) : base(message) { } } /// <summary> /// 模块异常 /// </summary> public class RegisteredException : HisException { /// <summary> /// /// </summary> /// <param name="message"></param> public RegisteredException(string message) : base(message) { } } }
Error的Action之所有调用到,是因为Configure中添加如下代码,把所有异常交给"/error"来处理。
app.UseExceptionHandler("/error");
添加dameiProblemDetailsFactory来兼容各类异常,自定义异常和Model验证异常
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.ModelBinding; using System.Collections.Generic; namespace WebApiError { /// <summary> /// /// </summary> public class dameiProblemDetailsFactory : ProblemDetailsFactory { /// <summary> /// 处理业务错误 /// </summary> /// <param name="httpContext"></param> /// <param name="statusCode"></param> /// <param name="title"></param> /// <param name="type"></param> /// <param name="detail"></param> /// <param name="instance"></param> /// <returns></returns> public override ProblemDetails CreateProblemDetails(HttpContext httpContext, int? statusCode = null, string title = null, string type = null, string detail = null, string instance = null) { var problem = new ProblemDetails() { Title = string.IsNullOrEmpty(type) ? title : $"业务异常错误:{title}", Detail = detail, Status = statusCode, Instance = instance, Type = type }; return problem; } /// <summary> /// 处理model验证错误 /// </summary> /// <param name="httpContext"></param> /// <param name="modelStateDictionary"></param> /// <param name="statusCode"></param> /// <param name="title"></param> /// <param name="type"></param> /// <param name="detail"></param> /// <param name="instance"></param> /// <returns></returns> public override ValidationProblemDetails CreateValidationProblemDetails(HttpContext httpContext, ModelStateDictionary modelStateDictionary, int? statusCode = null, string title = null, string type = null, string detail = null, string instance = null) { var problem = new ValidationProblemDetails() { Title = "Model验证错误", Detail = detail, Status = statusCode, Instance = instance, Type = type }; foreach (var a in modelStateDictionary) { var errorList = new List<string>(); foreach (var error in a.Value.Errors) { errorList.Add(error.ErrorMessage); } problem.Errors.Add(new keyvaluePair<string, string[]>(a.Key, errorList.ToArray())); } return problem; } } }
在ConfigureServices中需要注入dameiProblemDetailsFactory
services.AddTransient<ProblemDetailsFactory, dameiProblemDetailsFactory>();
其实还可以用Action过滤器来统一管理异常
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; namespace WebApiError { /// <summary> /// 自定义过滤器处理异常 /// </summary> public class dameiExceptionFilter : IActionFilter, IOrderedFilter { /// <summary> /// /// </summary> public int Order { get; } = int.MaxValue - 10; /// <summary> /// /// </summary> /// <param name="context"></param> public void OnActionExecuting(ActionExecutingContext context) { } /// <summary> /// /// </summary> /// <param name="context"></param> public void OnActionExecuted(ActionExecutedContext context) { if (context?.Exception != null) { context.Result = new ObjectResult(context.Exception.Message) { StatusCode = 500 }; context.ExceptionHandled = true; } } } }
另外一种方式是通过Action过滤器来处理
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; namespace WebApiError { /// <summary> /// 自定义过滤器处理异常 /// </summary> public class dameiExceptionFilter : IActionFilter, IOrderedFilter { /// <summary> /// /// </summary> public int Order { get; } = int.MaxValue - 10; /// <summary> /// /// </summary> /// <param name="context"></param> public void OnActionExecuting(ActionExecutingContext context) { } /// <summary> /// /// </summary> /// <param name="context"></param> public void OnActionExecuted(ActionExecutedContext context) { if (context?.Exception != null) { if (context.Exception is dameiException) { context.Result = new ObjectResult(context.Exception.Message) { Value = $"业务异常:{ context.Exception.Message}", StatusCode = 500 }; } else { context.Result = new ObjectResult(context.Exception.Message) { Value = context.Exception.Message, StatusCode = 500 }; } context.ExceptionHandled = true; } } } }
添加全局过滤器
services.AddControllers(options => { options.Filters.Add(new dameiExceptionFilter()); });
想要更快更方便的了解相关知识,可以关注微信公众号
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。