Loading... > 环境 `.Net 7.0` 项目 `ASP.NET Core WebAPI` ## 筛选器、过滤器、拦截器介绍 [ASP.NET Core 中的筛选器](https://learn.microsoft.com/zh-cn/aspnet/core/mvc/controllers/filters?view=aspnetcore-7.0) ![请求管道](https://learn.microsoft.com/zh-cn/aspnet/core/mvc/controllers/filters/_static/filter-pipeline-2.png?view%3Daspnetcore-7.0) ## 创建统一返回值基类 ```csharp public class BaseResultModel { public int? Code { get; set; } public string Message { get; set; } public object? Data { get; set; } public int ReturnStatus { get; set; } } ``` ## 拦截特性验证过滤器 ### IActionFilter 接口 | 编号 | 方法 | 说明 | | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | | 1 | [OnActionExecuted(ActionExecutedContext)](https://learn.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.mvc.filters.iactionfilter.onactionexecuted?view=aspnetcore-7.0#microsoft-aspnetcore-mvc-filters-iactionfilter-onactionexecuted(microsoft-aspnetcore-mvc-filters-actionexecutedcontext)) | 在操作执行后调用,然后执行操作结果。 | | 2 | [OnActionExecuting(ActionExecutingContext)](https://learn.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.mvc.filters.iactionfilter.onactionexecuting?view=aspnetcore-7.0#microsoft-aspnetcore-mvc-filters-iactionfilter-onactionexecuting(microsoft-aspnetcore-mvc-filters-actionexecutingcontext)) | 在操作执行之前调用,模型绑定完成后。 | ### 自定义验证过滤器 ```csharp /// <summary> /// 验证过滤器 /// </summary> public class MyValidationFilterAttribute : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { if (!context.ModelState.IsValid) // 是否通过验证 { var result = context.ModelState.Keys .SelectMany(key => context.ModelState[key]!.Errors.Select(x => new ValidationError(key, x.ErrorMessage))) .ToList(); context.Result = new ObjectResult(new BaseResultModel { Code = 400, Message = "error", Data = result, ReturnStatus = 0 }); } } public void OnActionExecuted(ActionExecutedContext context) { // throw new NotImplementedException(); } } ``` ### 添加过滤器 ![添加过滤器](https://hwcloud.sdqps.top/ShareImages/PicGo/20230208/638114669123627359.png) ### 解除默认限制 ```csharp builder.Services.Configure<ApiBehaviorOptions>(options => { options.SuppressModelStateInvalidFilter = true; }); ``` ### 创建业务 ```csharp // Person类用于接口请求数据 public class Person { [Range(1,10,ErrorMessage = "范围1-10")] public int Age { get; set; } [MinLength(2,ErrorMessage = "名称不能低于2个字符")] public string Name { get; set; } = String.Empty; } // API接口 [HttpPost] public Person AddPerson(Person input) { return input; } ``` ### 事例 ![未通过特性验证](https://hwcloud.sdqps.top/ShareImages/PicGo/20230208/638114650184879135.png) ![验证失败事例](https://hwcloud.sdqps.top/ShareImages/PicGo/20230209/638115468218120555.png) ![验证成功事例](https://hwcloud.sdqps.top/ShareImages/PicGo/20230208/638114644629132634.png) ## 拦截异常过滤器 ### IExceptionFilter 接口 | 编号 | 方法 | 说明 | | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | | 1 | [OnException(ExceptionContext)](https://learn.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.mvc.filters.iexceptionfilter.onexception?view=aspnetcore-7.0#microsoft-aspnetcore-mvc-filters-iexceptionfilter-onexception(microsoft-aspnetcore-mvc-filters-exceptioncontext)) | 在操作引发后 Exception调用 | ### 自定义异常过滤器 ```csharp /// <summary> /// 异常过滤器 /// </summary> public class MyExceptionFilterAttribute : IExceptionFilter { public void OnException(ExceptionContext context) { var exception = context.Exception; context.ExceptionHandled = true; context.Result = new ObjectResult(new BaseResultModel() { Code = 400, Message = exception.InnerException != null ? exception.InnerException.Message : exception.Message, Data = exception.Message, // 可改为其他值 ReturnStatus = 3 }); } } ``` ### 创建业务 ```csharp [HttpGet] public void ThrowException() { throw new Exception("抛出了一个异常"); } ``` ### 添加过滤器 ![添加异常拦截过滤器](https://hwcloud.sdqps.top/ShareImages/PicGo/20230209/638115483580308168.png) ### 事例 ![拦截异常](https://hwcloud.sdqps.top/ShareImages/PicGo/20230209/638115477037300903.png) ![验证异常拦截](https://hwcloud.sdqps.top/ShareImages/PicGo/20230209/638115477714188386.png) ## 操作筛选器 ### IActionFilter 接口 | 编号 | 方法 | 说明 | | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | | 1 | [OnActionExecuted(ActionExecutedContext)](https://learn.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.mvc.filters.iactionfilter.onactionexecuted?view=aspnetcore-7.0#microsoft-aspnetcore-mvc-filters-iactionfilter-onactionexecuted(microsoft-aspnetcore-mvc-filters-actionexecutedcontext)) | 在操作执行后调用,然后执行操作结果。 | | 2 | [OnActionExecuting(ActionExecutingContext)](https://learn.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.mvc.filters.iactionfilter.onactionexecuting?view=aspnetcore-7.0#microsoft-aspnetcore-mvc-filters-iactionfilter-onactionexecuting(microsoft-aspnetcore-mvc-filters-actionexecutingcontext)) | 在操作执行之前调用,模型绑定完成后。 | ### 自定义操作筛选器 ```csharp /// <summary> /// 操作拦截器 /// </summary> public class MyActionFilterAttribute : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { // throw new NotImplementedException(); } public void OnActionExecuted(ActionExecutedContext context) { var result = context.Result as ObjectResult; context.Result = new OkObjectResult(new BaseResultModel { Code = 200, Message = "success", Data = result?.Value, ReturnStatus = 1 }); } } ``` ### 创建业务 ```csharp [HttpPost] public DateTime GetNowTime() { return DateTime.Now; } ``` ### 添加过滤器 ![添加过滤器](https://hwcloud.sdqps.top/ShareImages/PicGo/20230209/638115494298148926.png) ### 事例 ![请求成功](https://hwcloud.sdqps.top/ShareImages/PicGo/20230209/638115492965267882.png) ## 使用拦截器统一返回值,将三个过滤器添加到配置中 ```csharp builder.Services.AddMvc(options => { options.Filters.Add<MyActionFilterAttribute>(); options.Filters.Add<MyExceptionFilterAttribute>(); options.Filters.Add<MyValidationFilterAttribute>(); }); ``` ## 优化 ### 原因 > 由于【特性拦截器】和【操作拦截器】都继承了IActionFilter接口,但拦截位置不同所以会出现异常信息包含在操作拦截器内(套娃现象),所以要修改两个拦截器内逻辑 ![套娃](https://hwcloud.sdqps.top/ShareImages/PicGo/20230209/638115516762350879.png) ### 解决一 > 取消特性验证拦截器,在操作拦截器内进行验证判断 ```csharp /// <summary> /// 操作拦截器 /// </summary> public class MyActionFilterAttribute : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { // throw new NotImplementedException(); } public void OnActionExecuted(ActionExecutedContext context) { if (!context.ModelState.IsValid) { var result = context.ModelState.Keys .SelectMany(key => context.ModelState[key]!.Errors.Select(x => new ValidationError(key, x.ErrorMessage))) .ToList(); context.Result = new ObjectResult(new BaseResultModel { Code = 400, Message = "error", Data = result, ReturnStatus = ReturnStatus.Fail }); } else { var statusCode = HttpStatusCode.OK; var result = context.Result as ObjectResult; context.Result = new OkObjectResult(new BaseResultModel { Code = (int)statusCode, Message = "success", Data = result?.Value, ReturnStatus = ReturnStatus.Success }); } } } ``` ### 解决二 ```csharp /// <summary> /// 操作拦截器 /// </summary> public class MyActionFilterAttribute : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { if (!context.ModelState.IsValid) { var result = context.ModelState.Keys .SelectMany( key => context.ModelState[key]!.Errors.Select(x => new ValidationError(key, x.ErrorMessage))) .ToList(); context.Result = new ObjectResult(new BaseResultModel { Code = 400, Message = "error", Data = result, ReturnStatus = ReturnStatus.Fail }); } } public void OnActionExecuted(ActionExecutedContext context) { var statusCode = HttpStatusCode.OK; var result = context.Result as ObjectResult; context.Result = new OkObjectResult(new BaseResultModel { Code = (int)statusCode, Message = "success", Data = result?.Value, ReturnStatus = ReturnStatus.Success }); } } ``` ## 完整代码 ```csharp /// <summary> /// 异常过滤器 /// </summary> public class MyExceptionFilterAttribute : IExceptionFilter { public void OnException(ExceptionContext context) { var exception = context.Exception; context.ExceptionHandled = true; context.Result = new ObjectResult(new BaseResultModel() { Code = 400, Message = exception.InnerException != null ? exception.InnerException.Message : exception.Message, Data = exception.Message, ReturnStatus = ReturnStatus.Error }); } } /// <summary> /// 操作拦截器/特性拦截器 /// </summary> public class MyActionFilterAttribute : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { if (!context.ModelState.IsValid) { var result = context.ModelState.Keys .SelectMany( key => context.ModelState[key]!.Errors.Select(x => new ValidationError(key, x.ErrorMessage))) .ToList(); context.Result = new ObjectResult(new BaseResultModel { Code = 400, Message = "error", Data = result, ReturnStatus = ReturnStatus.Fail }); } } public void OnActionExecuted(ActionExecutedContext context) { var statusCode = HttpStatusCode.OK; var result = context.Result as ObjectResult; context.Result = new OkObjectResult(new BaseResultModel { Code = (int)statusCode, Message = "success", Data = result?.Value, ReturnStatus = ReturnStatus.Success }); } } ``` 最后修改:2023 年 02 月 22 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 3 如果觉得我的文章对你有用,请随意赞赏