本文共 7239 字,大约阅读时间需要 24 分钟。
官方建议用app.UseExceptionHandler("/error")来集中处理异常,本例是一个具体的应用。
比如项目中有一个ViewModel,要求Name最大长度为5
////// 用户模型 /// public class UserModel { ////// ID /// public int ID { get; set; } //////名称 /// [MaxLength(5, ErrorMessage = "长度不能超过5")] public string Name { get; set; } }
在TestController中有两个Action,都有异常的机率,Get方法中,一个异常是系统内置的0被整除,另一个是我们自定义的业务层级异常(.NET架构小技巧(8)中有涉及);AddUser是有Model验证有可能Name超过5个字符后报异常。Error方法一个错误处理Action,根据上下文的异常来分流系统内置异常,还是自定业务异常。
////// get接口 /// ///[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(); } } /// /// 添加用户接口 /// /// ///[HttpPost("/adduser")] public IActionResult AddUser([FromBody] UserModel user) { return Ok(user); } /// /// 错误处理页 /// ///[HttpGet("/error")] public IActionResult Error() { var context = HttpContext.Features.Get (); //如果是业务自定义异常,进行特殊处理 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{ ////// 产品异常 /// public class DaMeiException : ApplicationException { ////// /// /// public DaMeiException(string message) : base(message) { } } ////// His项目异常 /// public class HisException : DaMeiException { ////// /// /// public HisException(string message) : base(message) { } } ////// Lis项目异常 /// public class LisException : DaMeiException { ////// /// /// public LisException(string message) : base(message) { } } ////// 模块异常 /// public class RegisteredException : HisException { ////// /// /// 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{ ////// /// public class DaMeiProblemDetailsFactory : ProblemDetailsFactory { ////// 处理业务错误 /// /// /// /// /// /// /// ///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; } /// /// 处理model验证错误 /// /// /// /// /// /// /// /// ///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 (); foreach (var error in a.Value.Errors) { errorList.Add(error.ErrorMessage); } problem.Errors.Add(new KeyValuePair (a.Key, errorList.ToArray())); } return problem; } }}
在ConfigureServices中需要注入DaMeiProblemDetailsFactory
services.AddTransient();
其实还可以用Action过滤器来统一管理异常
using Microsoft.AspNetCore.Mvc;using Microsoft.AspNetCore.Mvc.Filters;namespace WebApiError{ ////// 自定义过滤器处理异常 /// public class DaMeiExceptionFilter : IActionFilter, IOrderedFilter { ////// /// public int Order { get; } = int.MaxValue - 10; ////// /// /// public void OnActionExecuting(ActionExecutingContext context) { } ////// /// /// 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{ ////// 自定义过滤器处理异常 /// public class DaMeiExceptionFilter : IActionFilter, IOrderedFilter { ////// /// public int Order { get; } = int.MaxValue - 10; ////// /// /// public void OnActionExecuting(ActionExecutingContext context) { } ////// /// /// 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());});
转载地址:http://mtkdi.baihongyu.com/