可以看到,执行顺序和开篇的第一张图例一直,首先执行时资源过滤器的 OnResourceExecuting 方法,接着请求接入了 操作过滤器的 OnActionExecuting 方法,最后执行操作过滤器的 OnResultExecuting 方法,然后把请求交给资源过滤器的 OnResourceExecuted,最后返回到客户端
所以,从执行顺序可以看出,资源管理器的执行优先级总是高于操作过滤器
资源过滤器可以应用于控制器或者操作,然后基于其执行优先级的特点,开发员人员可以在资源过滤器中定义某些静态资源或者缓存直接将数据返回给客户端,并使其执行短路操作,减少后续管道请求步骤,以提高服务器响应性能
在服务器向客户端写入响应内容之前,如果系统引发了异常,异常过滤器可以捕获该异常,该过滤器作用于全局范围,这也是最常用的过滤器
5.1 创建一个异常过滤器
public class CustomerExceptionFilter : Attribute, IExceptionFilter { public void OnException(ExceptionContext context) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("发生了异常:{0}", context.Exception.Message); Console.ForegroundColor = ConsoleColor.Gray; } }5.2 将 CustomerExceptionFilter 应用到 HomeController 上
请注意,HomeController 上还同时应用了资源过滤器;现在要做到就是在资源过滤器内部抛出异常,看看 CustomerExceptionFilter 是否可以捕获该异常
public class CustomerResourceFilter : Attribute, IResourceFilter { public void OnResourceExecuted(ResourceExecutedContext context) { Console.WriteLine("==== OnResourceExecuted"); } public void OnResourceExecuting(ResourceExecutingContext context) { Console.WriteLine("==== OnResourceExecuting"); throw new Exception("资源管理器发生了异常"); } }5.3 运行程序,访问 :5000/api/home
可以看到,系统抛出了异常;但是,异常过滤器 CustomerExceptionFilter 并没有捕获该异常,事实证明资源过滤器的执行优先级还是高于异常过滤器,现在我们尝试在操作内部引发异常
[Route("api/[controller]")] [ApiController] [CustomerResourceFilter] [CustomerExceptionFilter] public class HomeController : ControllerBase { // GET api/values [HttpGet] [CustomerActionFilter] public async Task<ActionResult<IEnumerable<string>>> Get() { throw new Exception("Get操作发生了异常"); return new string[] { "value1", "value2" }; } }5.4 再次启动程序,访问 :5000/api/home,控制台输出结果如下
5.5 客户端得到了一个友好的返回值
5.6 这是因为我们在异常过滤器内部将异常进行了出来,并通过设置 context.ExceptionHandled = true 来标记表示异常已经被处理,然后输出友好信息
public class CustomerExceptionFilter : Attribute, IExceptionFilter { public void OnException(ExceptionContext context) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("发生了异常:{0}", context.Exception.Message); Console.ForegroundColor = ConsoleColor.Gray; context.Result = new JsonResult(new { code = 500, message = context.Exception.Message }); context.ExceptionHandled = true; } }异常过滤器的应用非常简单,你可以在其内部将异常写入日志,或者执行其它需要处理的逻辑
6. 操作过滤器 ActionFilterAttribute 和 结果过滤器 IResultFilter操作过滤器:当请求进入 API 接口的时候,操作过滤器提供了一个进入之前(before)和进入之后(after)介入功能,可以使用该过滤器对进入 API 的参数和结果进行干预
结果过滤器:这个过滤器的作用和操作过滤器非常相似,主要其作用范围是有微小区别的,结果过滤器是在操作即将返回结果到客户端之前(before)或者之后(after)执行干预,比如你可以在返回结果之后(after)去渲染视图
6.1 之所以将这两个过滤器放在一起讲,是因为,这两个过滤器就像一对孪生兄弟一样,正所谓有始有终,首先来看操作过滤器
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] public abstract class ActionFilterAttribute : Attribute, IActionFilter, IFilterMetadata, IAsyncActionFilter, IResultFilter, IAsyncResultFilter, IOrderedFilter { protected ActionFilterAttribute(); // public int Order { get; set; } // public virtual void OnActionExecuted(ActionExecutedContext context); // public virtual void OnActionExecuting(ActionExecutingContext context); // [AsyncStateMachine(typeof(<OnActionExecutionAsync>d__6))] public virtual Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next); // public virtual void OnResultExecuted(ResultExecutedContext context); // public virtual void OnResultExecuting(ResultExecutingContext context); // [AsyncStateMachine(typeof(<OnResultExecutionAsync>d__9))] public virtual Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next); }