Filter及其三种注册方式

一、Filter管道模型

在这里插入图片描述

二、各个Filter作用

前置Filter

1.Authorization

管道中第一个执行的Filter,这里首先处理权限信息,如果不通过不经过下面的filter节省资源

2.Resource

管道中第二个Filter,这里主要作用是对于缓存等资源做处理,如果有资源不再向下进行

3.Action

因为ActionFilter在模型绑定之后了,所以能进行数据的验证

 public void OnActionExecuting(ActionExecutingContext context)
        {
            if(!context.ModelState.IsValid)
            {
            //Result相当一个短路器,当result有值了,就会返回给前端结果,而不再向下执行
            	context.Result = new BadRequestObjectResult(context.ModelState);
            }
        }

这里可以做用户的行为日志记录等记录。因为再授权或者资源filter中做的话,可能授权不过,还是做了用户访问行为日志。所以放在Action过滤器中

 public void OnActionExecuting(ActionExecutingContext context)
        {   
        //过滤器直接使用构造函数注入logger会有异常,这里是手动注入logger,或者可以再控制器中使用TypeFilter(自行查找方法)来实现注入。
            var logger = context.HttpContext.RequestServices.GetService<ILogger<TestFilterAttribute>>();
            //获取访问路径
            var path = context.HttpContext.Request.Path;
            //获取访问的控制器
            var controller = context.RouteData.Values["controller"];
            //获取访问的方法
            var action = context.RouteData.Values["action"];
            //获取访问的参数
            var arguments = string.Join(",",context.ActionArguments);
            //这里可以结合ES来记录用户的访问行为日志。
            logger.LogInformation($"访问的路由{path},控制器是{controller},行为是{action},参数是{arguments}");
        }

3.1 TypeFilter&ServiceFilter

以这种方式标注到控制器中,那么在ActionFilter中就能正常的依赖注入了。

[TypeFilter(typeof(TestFilterAttribute))]
public class WeatherForecastController : ControllerBase
{
}

通过ServiceFilter注册事,需要对创建的过滤器进行注册

[ServiceFilter(typeof(TestFilterAttribute))]
public class WeatherForecastController : ControllerBase
{
}

program中注册

builder.Services.AddSingleton<TestFilterAttribute>();

4.Exception

当发生异常时,可以在这里统一处理发生的异常。

Exception作用域

上面的图位置有问题,图中ResourceFilter后直接进入到ActionFilter中,但是源码中是直接进入到ExcetionFilter中。
Exception是在Authorization和Resource的Filter之后才进入到ExceptionFilter中,所以这两个出现异常无法呗Exception捕获。

当进入到ActionFilter中,出现的异常

三、定义Filter(以ResultFilter为例)

    public class ResultFilterAttribute :Attribute, IResultFilter
    {
        public void OnResultExecuted(ResultExecutedContext context) { }
        //在操作结果执行之前调用
        public void OnResultExecuting(ResultExecutingContext context)
        {
            switch (context)
            {
            //根据的数据类型进行处理
                case ResultExecutingContext resultExecutingContext:
                    switch (resultExecutingContext.Result)
                    {
                        case ObjectResult content:
                            var contentResp = new AjaxResponse<object>(content.Value);
                            context.Result = new ObjectResult(contentResp);
                            break;
                        case JsonResult json:
                        //AjaxResposne对Result封装,统一响应信息  Message Code Success  Data 这四个值
                            var resp = new AjaxResponse<object>(json.Value);
                            context.Result = new ObjectResult(resp);
                            break;
                        case EmptyResult empty:
                            context.Result = new OkObjectResult(AjaxResponse<object>.Successed());
                            break;
                        default:
                            break;
                    }
                    break;
            }
        }
    }

四、全局注册Filter

  services.AddControllersWithViews(
                options => {
                    options.Filters.Add(typeof(ResultFilterAttribute ));
                }
                )

五、类级别以及Action级别注册Filter

namespace FirstDemo.Controllers
{
	//通过属性标注对整个类进行过滤
    [ResultFilter]
    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;

        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
        }
        //通过属性标注该方法进行过滤
        [ResultFilter]
        public IActionResult Index()
        {
            return View();
        }
        
        public IActionResult Privacy()
        {
            return View();
        }

        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }
    }
}

六、类级与Action级的区别

如果同时在controller以及方法上标注了Filter,会先执行类级别的Filter再执行Action级别

posted @ 2022-08-11 22:01  有诗亦有远方  阅读(129)  评论(0)    收藏  举报  来源