Filter及其三种注册方式
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级别