ASP.NET Core MVC 过滤器(Filter) |
一.过滤器如何工作不同的过滤器类型在管道中的不同阶段执行,因此具有各自的与其场景 。根据需要执行的任务以及需要执行的请求管道中的位置,选择要创建的过滤器类型 。过滤器在 MVC 操作调用管道中运行,有时也称为过滤管道,在 MVC 中选择要执行的操作后,执行操作上的过滤器,如图:
不同的过滤器在管道内的不同位置执行 。像授权过滤器这样的过滤器只在管道中靠前的位置执行 。其他过滤器,如操作(Action)过滤器,可以在管道执行的其他部分之前和之后执行,如图:
1.选择过滤器授权过滤器用于确定当前请求用户是否被授权 。 资源过滤器是在授权之后第一个处理请求的过滤器,也是最后一个在请求离开过滤管道时接触请求的过滤器 。在性能方面,对实现缓存或者对过滤管道进行短路 特别有用 。 操作过滤器包装对单个操作方法的调用,并且可以处理传递到操作的参数以及从操作返回的操作结果 。 异常过滤器用于对 MVC 应用程序中未处理的异常应用全局策略 。 结果过滤器包装单个操作结果的执行,并且尽在操作执行成功时运行 。它们必须是围绕视图执行或格式化程序执行的逻辑的理想选择 。 2.实现过滤器所有过滤器均可通过不同的接口定义支持同步和异步的实现 。根据需要执行的任务类型,选择同步或异步实现 。从框架的角度看,它们是可以互换的 。 同步过滤器定义了
public class SampleActionFilter:IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
//操作执行前做的事情
}
public void OnActionExecuted(ActionExecutedContext context)
{
//操作执行后做的事情
}
}
异步过滤器定义了一个单一的
public class SampleAsyncActionFilter: IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
//操作执行前做的事情
await next();
//操作执行后做的事情
}
}
3.过滤器作用域 过滤器有三种不同级别的作用域 。你可以在特定的操作上用特性( 如果想要使用全局过滤器,可以在配置 MVC 时,在
services.AddMvc(options =>
{
options.Filters.Add(typeof(SampleActionFilter));//通过类型
options.Filters.Add(new SampleActionFilter());//注册实例
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
过滤器既可以通过类型添加,也可以通过实例添加 。如果通过实例添加,则该实例会被使用于每一个请求 。如果通过类型添加,则在每次请求后都会创建一个实例,其所有构造函数依赖项都将通过 DI 来填充 。 把过滤器接口的实现当作特性使用也非常方便 。过滤器特性可应用于控制器和操作方法 。框架包含了内置的基于特性的过滤器,可以继承他们或者另外定制 。例如,下面的过滤器继承了
public class AddHeaderAttribute: ResultFilterAttribute
{
private readonly string _name;
private readonly string _value;
public AddHeaderAttribute(string name, string value)
{
_name = name;
_value = value;
}
public override void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.Headers.Add(
_name,new string[] { _value });
base.OnResultExecuting(context);
}
}
特性允许过滤器接受参数,如下,可将此特性添加到控制器或操作中,并为其指定所需 HTTP 头的名称和值: [AddHeader("Author", "Ruby Lu")]
public class HomeController : Controller
{
}
以下几种过滤器接口可以自定义为相应特性的实现:
4.取消和短路 通过设置传入过滤器方法的上下文参数中的 Result 属性,可以在过滤器管道的任意一点短路管道 。比如,下面的
public class ShortCircuitingResourceFilter:Attribute,IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext context)
{
context.Result = new ContentResult() {
Content = "短路"
};
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
}
}
二.配置过滤器 全局过滤器在 1.依赖注入以特性形式实现的,直接添加到控制器或操作的过滤器,其构造函数不得由依赖注入提供依赖项 。其原因在于,特性所需的构造函数参数必须由使用处直接提供 。这是特性原型机理的限制 。 如果过滤器需要从 DI 中获得依赖项,那么可以用以下几种方法在类或操作方法使用:
先在 然后使用:
[ServiceFilter(typeof(AddHeaderFilterWithDI))]
public IActionResult Index()
{
}
由于这种差异,使用
[TypeFilter(typeof(AddHeaderAttribute),Arguments =new object[] { "Author","Ruby" })]
public IActionResult Index()
{
return View();
}
如果有一个简单的过滤器,不需要任何参数,但有构造函数需要通过 DI 填充依赖项,那么可以继承
public class SampleActionFilterAttribute:TypeFilterAttribute
{
public SampleActionFilterAttribute() : base(typeof(SampleActionFilterImpl))
{
}
private class SampleActionFilterImpl:IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
//操作执行前做的事情
}
public void OnActionExecuted(ActionExecutedContext context)
{
//操作执行后做的事情
}
}
}
该过滤器可通过使用 [ 你可以在自己地特性中实现
public class AddHeadWithFactoryAttribute:Attribute, IFilterFactory
{
public bool IsReusable { get; }
//实现IFilterFactory
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return new InternalAddHeaderFilter();
}
}
public class InternalAddHeaderFilter : IResultFilter
{
public void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.Headers.Add(
"Internal", new string[] { "Header Add" });
}
public void OnResultExecuted(ResultExecutedContext context)
{
}
}
2.排序过滤器可以应用于操作方法或控制器(通过特性)或添加到全局过滤器集合中 。作用域通常也决定了排序,最接近操作的过滤器首先运行 。 除了作用域,过滤器还可以通过实现 每个从
要修改默认的基于范围的顺序,则应显示设置类级别或者方法级别过滤器的 [MyFilter (Name = "...",Order = -1)] 在这种情况下,小于零的值将确保此过滤器在全局和类级过滤器之前运行:
3.对比中间件一般来说,过滤器用于处理业务与应用程序的横切关注点,用法和功能很像中间件,但过滤器允许你将作用范围缩小,并将其插入到应用程序中有意义的位置,例如视图之前或模型绑定之后 。过滤器是 MVC 的一部分,可以访问其上下文和构造函数 。例如,中间件很难检测到请求的模型验证是否产生错误,并且做出相应的响应 。 到此这篇关于 |