ASP.NET Core – Filter
介绍
Filter 类似 Middleware,只是它集中在处理 request 的前后,
站 MVC 角度看就是 before 和 after action,
站 Razor Pages 角度就是 before PageModel after

参考
Docs – Filters in ASP.NET Core(MVC Filter)
Docs – Filter methods for Razor Pages in ASP.NET Core(Razor Pages Filter)
Razor Pages – Filter
IPageFilter & IAsyncPageFilter
先讲 Razor Pages 的 Filter 吧。
IPageFilter 和 IAsyncPageFilter 这两个是 Razor Pages 主要的 Filter,两个拦截的点是一样的,只是一个 for sync 一个 for async。
public class MyPageFilter : IPageFilter
{
public void OnPageHandlerSelected(PageHandlerSelectedContext context)
{
// 1. before PageModel.OnGet
} public void OnPageHandlerExecuting(PageHandlerExecutingContext context)
{
// 2. before PageModel.OnGet
} public void OnPageHandlerExecuted(PageHandlerExecutedContext context)
{
// 3. after PageModel.OnGet, but before View
}
}
它有 3 个点可以拦截,主要就是 PageModel.OnGet 之前和之后。context 可以拿到很多资料,比如 Request,当前 PageModel 的 class Type 等等。
再看 Async 的。
public class MyAsyncPageFilter : IAsyncPageFilter
{
public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
{
// 1. before PageModel.OnGet
return Task.CompletedTask;
} public Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next)
{
// 2. before PageModel.OnGet
return next.Invoke();
// 3. after PageModel.OnGet, but before View
}
}
虽然它少了一个 overload method,但同样有 3 个拦截点。所以 IPageFilter,IAsyncPageFilter 本质是一样的,只是看我们拦截后是否有需要异步来做选择就可以了。
Apply Global Filter
定义好 IPageFilter 后,我们还得 apply 它。到 program.cs 把 filter 添加进去就可以了。
builder.Services.AddRazorPages().AddMvcOptions(options =>
{
options.Filters.Add(new MyPageFilter());
options.Filters.Add(new MyAsyncPageFilter());
});
注: 它虽然是 Razor Pages Filter 但却是添加到 MvcOptions 里头哦。
注: 执行顺序和我们 apply filter 的顺序是有关系的哦。

如果我们先 Add AsyncFilter 顺序就不是上面这样了,但我认为我们不应该依赖这个顺序去做逻辑啦,不然会很管理的,不顺风水。
Dependancy Injection in Filter
上面我们 apply filter 的时候是用实例化 new MyPageFilter() 这种方式。所以它不支持 DI。
若需要 DI,我们得这样。
builder.Services.TryAddScoped<MyService>();
builder.Services.AddRazorPages().AddMvcOptions(options =>
{
options.Filters.Add(typeof(MyPageFilter));
options.Filters.Add(typeof(MyAsyncPageFilter));
});
把实例化 new MyPageFilter() 改成 typeof(MyPageFilter)。
接着就能依赖注入了。

注:typeof(MyPageFilter) 是 scope level,每一个请求都会重新实例化一个 MyPageFilter。而 new MyPageFilter() 则始终是一个对象。
ServiceFilterAttribute
通常 Filter 需要 DI,我们会更倾向于使用 ServiceFilterAttribute。
builder.Services.TryAddScoped<MyPageFilter>();
builder.Services.AddRazorPages().AddMvcOptions(options =>
{
options.Filters.Add(new ServiceFilterAttribute(typeof(MyPageFilter)) { IsReusable = true });
});
首先把 MyPageFilter 添加进 DI。然后添加 Filter。
它多了一个配置 IsReusable,IsReusable 可以让 Filter 变成单列模式。这样就不需要每一次请求都重新实例化 Filter 了。
ServiceFilterAttribute 不只这一个功能,我们继续往下看。
Filter on Specify Page
上面我们是 apply global,每一个 page 都会被这个 Filter 拦截。
如果我们只想拦截某一些 pages,我们也可以利用 ServiceFilterAttribute。
builder.Services.TryAddScoped<MyPageFilter>();
builder.Services.AddRazorPages();
我们依然需要把 MyPageFilter 添加到 DI,但是不需要添加 Filter 了。
取而代之的是在想要拦截的 PageModel 上添加 Attribute。
[ServiceFilter<MyPageFilter>(IsReusable = true)]
public class IndexModel : PageModel {}
TypeFilterAttribute
既然已经介绍了 ServiceFilterAttribute 那就顺便介绍 TypeFilter。
它和 ServiceFilterAttribute 非常像,区别是它可以在声明 Attribute 时传参数。
假设我们的 MyPageFilter 需要一个参数 value,这个参数和 _myService 不同,它不来自 DI。

在声明 Attribute 时,传入参数。
[TypeFilter<MyPageFilter>(Arguments = ["value"], IsReusable = true)]
public class IndexModel : PageModel {}
注意:

TypeFilter 不是直接通过 DI 来创建的,所以 MyPageFilter 不需要,也不可以添加到 DI。

IResultFilter & IAsyncResultFilter
IPageFilter 拦截的是 PageModel.OnGet 前后,而且是 before View。
IResultFilter 则是拦截 View 前后。它的用法和 IPageFilter 完全一样,只是拦截的点不同而已。
public class MyResultFilter : IResultFilter
{
public void OnResultExecuting(ResultExecutingContext context)
{
// 1. before View, but after IPageFilter.OnPageHandlerExecuted
} public void OnResultExecuted(ResultExecutedContext context)
{
// 4. after view
}
} public class MyAsyncResultFilter : IAsyncResultFilter
{
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
// 2. before View
await next.Invoke(); // running View
// 3. after View
}
}
apply 的方式是一样的
builder.Services.AddRazorPages().AddMvcOptions(options =>
{
options.Filters.Add(new MyResultFilter());
options.Filters.Add(new MyAsyncResultFilter());
});
ResultFilterAttribute
ResultFilterAttribute 底层是 IResultFilter,只是 ASP.NET Core wrap 了一层 Attribute 而已。
好处就是可以直接指定 apply to specify page。不过如果需要 DI 的话,那依然要 wrap Service/TypeFilterAttribute 哦。
ResultFilterAttribute 同时实现了 IResultFilter 和 IAsyncResultFilter 的拦截点。
public class MyResultFilter : ResultFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext context)
{
// before
base.OnResultExecuting(context); // before
} public override void OnResultExecuted(ResultExecutedContext context)
{
// after
base.OnResultExecuted(context); // after
} public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
// before
await base.OnResultExecutionAsync(context, next); // before > View > after
// after
}
}
不需要去 program.cs 做 apply,只要把 Attribute apply 到 PageModel 就可以了。
[MyResultFilter]
public class IndexModel : PageModel {}
Mvc – Filter
ActionFilterAttribute
它相等于 IPageFilter + IResultFilter + wrap attribute。
public class MyActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
// 2. before action
base.OnActionExecuting(context);
// running action
}
public override void OnActionExecuted(ActionExecutedContext context)
{
// 3. after action
base.OnActionExecuted(context);
}
public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// 1. before action
return base.OnActionExecutionAsync(context, next);
// 4. after action but before View
} public override void OnResultExecuting(ResultExecutingContext context)
{
// 6. before View
base.OnResultExecuting(context);
// running View
}
public override void OnResultExecuted(ResultExecutedContext context)
{
// 7. after View
base.OnResultExecuted(context);
}
public override Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
// 5. before View
return base.OnResultExecutionAsync(context, next);
// 8. after View
}
}
同样的,如果需要 DI 任然要 wrap Service/TypeFilterAttribute 哦。
总结
1. Filter 有 sync 和 async 两个版本。
比如:IPageFilter vs IAsyncPageFilter
它们接口可能有微微不同,但可拦截地方是一样多的。
2. 拦截点
before PageModel / Controller
after PageModel / Controller
before View
after View
3. Razor Pages 需要 IPageFilter + IResultFilter 才能拦截完所有地方。Mvc 只要一个 ActionFilter 就可以了。
4. IPageFilter、IResultFilter、IActionFilter 都是底层接口。必须 apply to global。
5. ResultFilterAttribute、ActionFilterAttribute 是 Attribute 版,可以 apply to global 也可以选择只 apply to specify PageModel 或 Controller,没有 PageFilterAttribute 的哦。
6. IPageFilter、IResultFilter、IActionFilter 如果要 DI,可以在 apply to global 时使用 typeof(),取代实例化。
7. FilterAttribute 要 DI 的话,需要使用 ServiceFilterAttribute,记得把 FilterAttribute 添加到 DI 中。
8. FilterAttribute 要参数的话,需要使用 TypeFilterAttribute,不要把 FilterAttribute 添加到 DI 中,会报错的,不用担心,它本来就支持 DI 了。
ASP.NET Core – Filter的更多相关文章
- Asp.Net Core Filter 深入浅出的那些事-AOP
一.前言 在分享ASP.NET Core Filter 使用之前,先来谈谈AOP,什么是AOP 呢? AOP全称Aspect Oriented Programming意为面向切面编程,也叫做面向方法编 ...
- ASP.NET Core Filter如何支持依赖注入
通过Filter来支持:分别有IResourceFilter AuthorizeFilter ActionFilter ExceptionFilter ResultFilter,Filter也被称为拦 ...
- ASP.NET Core Filter与IOC的羁绊
前言 我们在使用ASP.NET Core进行服务端应用开发的时候,或多或少都会涉及到使用Filter的场景.Filter简单来说是Action的拦截器,它可以在Action执行之前或者之后对请求信息进 ...
- Asp.net Core Filter过滤器异常处理
本文旨在: 1 继承ExceptionFilterAttribute,重写Override OnException(ExceptionContext context)处理异常 2 在.netCore中 ...
- Asp.Net Core 进阶(四)—— 过滤器 Filters
一.介绍 Asp.Net Core Filter 使得可以在请求处理管道的特定阶段的前后执行代码,我们可以创建自定义的 filter 用于处理横切关注点. 横切关注点的示例包括错误处理.缓存.配置.授 ...
- Asp.Net Core Endpoint 终结点路由之中间件应用
一.概述 这篇文章主要分享Endpoint 终结点路由的中间件的应用场景及实践案例,不讲述其工作原理,如果需要了解工作原理的同学, 可以点击查看以下两篇解读文章: Asp.Net Core EndPo ...
- ASP.NET Core 2.2 十八.各种Filter的内部处理机制及执行顺序
ASP.NET core 的Filter是系统中经常用到的,本文详细分享一下各种Filter定义.执行的内部机制以及执行顺序.(ASP.NET Core 系列目录) 一. 概述 ASP.NET Cor ...
- ASP.NET Core 中间件 中间件(Middleware)和过滤器(Filter)的区别
https://www.cnblogs.com/savorboard/p/5586229.html 前言 在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际使用的, ...
- ASP.NET CORE MVC 2.0 如何在Filter中使用依赖注入来读取AppSettings,及.NET Core控制台项目中读取AppSettings
问: ASP.NET CORE MVC 如何在Filter中使用依赖注入来读取AppSettings 答: Dependency injection is possible in filters as ...
- [转]Create Custom Exception Filter in ASP.NET Core
本文转自:http://www.binaryintellect.net/articles/5df6e275-1148-45a1-a8b3-0ba2c7c9cea1.aspx In my previou ...
随机推荐
- 解读MySQL 8.0数据字典缓存管理机制
背景介绍 MySQL的数据字典(Data Dictionary,简称DD),用于存储数据库的元数据信息,它在8.0版本中被重新设计和实现,通过将所有DD数据唯一地持久化到InnoDB存储引擎的DD t ...
- 题解:P10320 勇气(Courage)
P10320 勇气(Courage) 推导过程 本题是一道数学题,重点是如何推导出正确式子. 首先,先特判几个特殊点: 当 \(n>=2\) 且 \(x=2\) 时,是不存在解的,战斗力无论何时 ...
- 很呆的一个问题:我的新项目又找不到mapper这个bean了
1.选springboot版本 <properties> <java.version>8</java.version> <project.build.sour ...
- Diffutoon下载介绍:真人视频转动漫工具,轻松获得上千点赞
最近在刷短视频的时候,偶尔能看到一些真人转动漫风的作品,看起来给人一种新鲜感,流量都还不错,简简单单跳个舞,就能获得上千个点赞~ 那么,这种视频是怎么制作的? 本期给大家介绍一款AI转绘工具Diffu ...
- 使用MySQL实现分布式锁
分布式锁开发中经常使用,在项目多节点部署或者微服务项目中,JAVA提供的线程锁已经不能满足安全的需求,需要使用全局的分布式锁来保证安全:分布式锁的实现的方式有很多种,最常见的有zookeeper,Re ...
- 【转载】冲压过程仿真模拟及优化 —— 冲压仿真的方法分类PPT
地址: https://www.renrendoc.com/paper/310415051.html
- 【转载】 DeepMind 提出元梯度强化学习算法,显著提高大规模深度强化学习应用的性能
原文地址: https://www.jiqizhixin.com/articles/053104 李亚洲翻译 2018/05/31 12:38 Pedro 路参与 ================== ...
- WarpDrive 教程 第一部分修改版
本文参考: https://www.cnblogs.com/devilmaycry812839668/p/15327509.html warpDrive是一个python库,目的是使用GPU并行运行多 ...
- deepin国产操作系统 nvidia-docker2 的安装
====================================== 平时偶尔使用deepin系统,突然有个 nvidia-docker 的程序需要运行,平时工作都是在用Ubuntu,所以对d ...
- 面试官:说说volatile应用和实现原理?
volatile 是并发编程中的重要关键字,它的名气甚至是可以与 synchronized.ReentrantLock 等齐名,也是属于并发编程五杰之一. 需要注意的是 volatile 并不能保证原 ...