【ASP.NET Core】MVC过滤器:运行流程
MVC 的过滤器(Filters)也翻译为“筛选器”。但是老周更喜欢翻译为“过滤器”,意思上更好理解。
既然都叫过滤器了,就是在MVC的操作方法调用前后进行特殊处理的类型。比如:
a、此调用是否已授权?
b、在模型绑定之前要不要修改数据源?(可能含有儿童不宜的数据)
c、在调用MVC方法前要不要改一改输入参数?在MVC方法调用之后要不要处理一下结果(加点味精,进一步调味)
d、发生异常后怎么处理?
过滤器可解决上面一堆提问。
在 ASP.NET Core 的 MVC 框架中,所有过滤器都实现共同接口 IFilterMetadata。该接口空空如也,未定义任何成员。说白了,它的用处是作为一种“记号”。你怎么证明你就是过滤器,嗯,看看你实现了 IFilterMetadata 接口没?实现了就认定是过滤器。所以,该接口纯粹是个角色标签。
咱们写代码一般不会实现 IFilterMetadata 接口,毕竟里面什么卵方法都没有,怎么规范类型?因此,过滤器专属命名空间 Microsoft.AspNetCore.Mvc.Filters 下为我们公开了以下接口,方便开发者实现:
1、IAuthorizationFilter:授权过滤器,它的优先级最高,总是最先运行。看看你有没有权限调用 MVC 方法,若没权限,就 See you La La。
2、IResourceFilter:资源过滤器。它在授权过滤成功后、模型绑定前运行。可以检查一下用于绑定的数据,要不要改一下。
3、IActionFilter:操作方法过滤器,就是针对 MVC Action 的。在操作方法运行前后运行,可以用来修改输入参数值。
4、IResultFilter:结果过滤器。当 MVC 操作方法运行成功后就会运行,可以用来修改运行结果。比如加点 HTTP 消息头什么的。
5、IExceptionFilter:当 MVC 操作方法运行过程中发生异常才会运行,无异常就不会运行。
…… 其实还有的,但这里咱们先不提,免得大伙搞得头晕。
过滤器不止一个,同一类型的过滤还可能有多个,因此,它们就像中间件那样,一个个链接起来,形成下水沟,哦不,是调用管道,或叫调用栈。于是,这就出现谁先运行的问题,虽然上面的介绍有说明,不过那太抽象了。任何编程知识只要能用代码来验证和观察,就不用图表和理论。
下面,咱们实现上述几个接口,然后往控制台上打印一些文本,来看看这些过滤器是怎么运行的。
public class CustAuthFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
Console.WriteLine("授权过滤器运行");
}
} public class CustResourceFilter : IResourceFilter
{
public void OnResourceExecuted(ResourceExecutedContext context)
{
Console.WriteLine("资源过滤器 - " + $"{nameof(OnResourceExecuted)}方法运行");
} public void OnResourceExecuting(ResourceExecutingContext context)
{
Console.WriteLine("资源过滤器 - " + $"{nameof(OnResourceExecuting)}方法运行");
}
} public class CustActionFilter : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine("操作过滤器 - " + $"{nameof(OnActionExecuted)}方法运行");
} public void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine("操作过滤器 - " + $"{nameof(OnActionExecuting)}方法运行");
}
} public class CustResultFilter : IResultFilter
{
public void OnResultExecuted(ResultExecutedContext context)
{
Console.WriteLine("结果过滤器 - " + $"{nameof(OnResultExecuted)}方法运行");
} public void OnResultExecuting(ResultExecutingContext context)
{
Console.WriteLine("结果过滤器 - " + $"{nameof(OnResultExecuting)}方法运行");
}
}
这里我没有实现异常过滤器,只实现了授权、资源、操作方法、结果这几个有代表性的。
授权过滤器只要实现 OnAuthorization 方法即可。在实现代码中,可以通过 HttpContext 对象查找授权有关的对象,如果确认是没有访问权限的,可以设置一个自己定 Result 让 MVC 操作方法的调用终止。
资源过滤器要实现两个方法:OnResourceExecuting 方法在模型绑定前调用,这时你有机会修改数据源;OnResourceExecuted 方法是在资源过滤之后的其他过滤器运行结束才被调用,即:
ResourceExecuting
........ 剩余过滤器.......
ResourceExecuted
Action 过滤器也要实现两个方法:OnActionExecuting 在操作调用前运行;OnActionExecuted 是在操作方法调用后运行。
结果过滤器需要实现两个方法:OnResultExecuting 方法在操作结果执行前调用,这里可以修改 MVC 方法返回的值;OnResultExecuted 方法是在操作结果执行之后调用,一般这里可以改改HTTP向应头、Cookie 什么的。
其实咱们刚实现的过滤器都是同步版本,这些过滤器都有配套的异步版本,接口都是以 IAsync 开头。这里咱们先不用管同步异步,避免搞得复杂了。也不要去理会过滤器是全局的还是局部的,下面咱们统一把它们注册为全局的。配置方法是通过 MVC 选项类的 Filters 集合,把要用的过滤器添加进去即可。
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews(options =>
{
// 配置全局过滤器
options.Filters.Add<CustAuthFilter>();
options.Filters.Add<CustResourceFilter>();
options.Filters.Add<CustActionFilter>();
options.Filters.Add<CustResultFilter>();
});
var app = builder.Build();
添加一个“狗头”控制器,用于测试。
public class GouTouController : Controller
{
public IActionResult Index()
{
Console.WriteLine("Index操作运行");
return View();
}
}
为了防止 ASP.NET Core 应用程序输出的日志干扰咱们查看控制台内容,咱们禁用所有日志输出。打开 appsettings.json 文件,把所有日志类别的记录级别改为 None。
{
"Logging": {
"LogLevel": {
"*": "None"
}
},
"AllowedHosts": "*"
}
星号 * 的意思就是代表所有类别的日志,LogLevel 为 None 就不会输出日志了(貌似有个别日志禁用不了)。
运行程序后,控制台打印出这样的内容:

这个流程现在是不是很清晰了?咱们画图表了,直接这样表达就好:
Author
Resource Executing
Action Executing
Action Running
Action Executed
Result Executing
Result Running
Result Executed
Resource Executed
局部过滤器的运行过程与全局过滤器相同,如果局部和全局过滤器同时使用,那会发生什么呢?咱们试试。
接下来我们为授权过滤、资源过滤、操作过滤、结果过滤各创建两个类——用于局部和全局。实际开发中一般不需要这样搞,通常全局和局部写一个类就行,毕竟过滤器类型在全局和局部是通用的。我这里只为了演示。局部过滤器是通过特性类的方式应用到 MVC 方法上的,所以,局部过滤器除了实现过滤器接口,还要从 Attribute 类派生。
1、实现局部、全局授权过滤器。
// 授权过滤器-局部
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class MyAuthorFilterAttribute : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
Console.WriteLine("局部:授权过滤器运行");
}
} // 授权过滤器-全局
public class GlobAuthorFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
Console.WriteLine("全局:授权过滤器运行");
}
}
2、实现局部、全局资源过滤器。
// 资源过滤器-局部
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class MyResourceFilterAttribute : Attribute, IResourceFilter
{
public void OnResourceExecuted(ResourceExecutedContext context)
{
Console.WriteLine("局部:资源过滤器-Executed");
} public void OnResourceExecuting(ResourceExecutingContext context)
{
Console.WriteLine("局部:资源过滤器-Executing");
}
} // 资源过滤器-全局
public class GlobResourceFilter : IResourceFilter
{
public void OnResourceExecuted(ResourceExecutedContext context)
{
Console.WriteLine("全局:资源过滤器-Executed");
} public void OnResourceExecuting(ResourceExecutingContext context)
{
Console.WriteLine("全局:资源过滤器-Executing");
}
}
3、实现局部、全局操作过滤器。
// 操作过滤器-局部
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class MyActionFilterAttribute : Attribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine("局部:操作过滤器-Executed");
} public void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine("局部:操作过滤器-Executing");
}
} // 操作过滤器-全局
public class GlobActionFilter : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine("全局:操作过滤器-Executed");
} public void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine("全局:操作过滤器-Executing");
}
}
4、实现局部、全局结果过滤器。
// 结果过滤器-局部
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class MyResultFilterAttribute : Attribute, IResultFilter
{
public void OnResultExecuted(ResultExecutedContext context)
{
Console.WriteLine("局部:结果过滤器-Executed");
} public void OnResultExecuting(ResultExecutingContext context)
{
Console.WriteLine("局部:结果过滤器-Executing");
}
} // 结果过滤器-全局
public class GlobResultFilter : IResultFilter
{
public void OnResultExecuted(ResultExecutedContext context)
{
Console.WriteLine("全局:结果过滤器-Executed");
} public void OnResultExecuting(ResultExecutingContext context)
{
Console.WriteLine("全局:结果过滤器-Executing");
}
}
先注册全局过滤器。
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(options =>
{
// 添加全局过滤器
options.Filters.Add<GlobActionFilter>();
options.Filters.Add<GlobAuthorFilter>();
options.Filters.Add<GlobResourceFilter>();
options.Filters.Add<GlobResultFilter>();
});
var app = builder.Build();
局部过滤器以特性方式应用于 MVC 操作方法。
public class SpiderController : ControllerBase
{
[MyResourceFilter]
[MyResultFilter]
[MyActionFilter, MyAuthorFilter]
public IActionResult Index()
{
Console.WriteLine("Index操作被调用");
return Content("大火烧了毛毛虫");
}
}
和上一个例子一样,禁用日志输出(appsettings.json文件)。
{
"Logging": {
"LogLevel": {
"*": "None"
}
},
……
}
程序运行后,控制台打印以下内容:

过滤器按 授权->资源->操作->结果 运行的次序不变。在同种过滤器中,全局过滤器优先运行。
全局授权过滤器
局部授权过滤器
全局资源过滤器 - 前
局部资源过滤器 - 前
全局操作过滤器 - 前
局部操作过滤器 - 前
【调用 MVC 操作方法】
局部操作过滤器 - 后
全局操作过滤器 - 后
全局结果过滤器 - 前
局部结果过滤器 - 前
【执行操作结果】
局部结果过滤器 - 后
全局结果过滤器 - 后
局部资源过滤器 - 后
全局资源过滤器 - 后
另外,有一件事要注意:如果你的控制器的基类是 Controller,那么,还有优先更高的 Action Filter。看看 Controller 类它实现了啥接口。
public abstract class Controller : ControllerBase, IActionFilter, IFilterMetadata, IAsyncActionFilter, IDisposable
咱们把刚才的控制器代码改一下,让它继承 Controller 类,并重写 OnActionExecuting、OnActionExecuted 方法。
public class SpiderController : Controller
{
…… public override void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine("控制器实现的操作过滤器-Executing");
base.OnActionExecuting(context);
} public override void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine("控制器实现的操作过滤器-Executed");
base.OnActionExecuted(context);
}
}
然后再次运行程序,控制台将打印以下内容:

看,这个由控制器类实现的 Action 过滤器比全局的还早运行。
【ASP.NET Core】MVC过滤器:运行流程的更多相关文章
- 解说asp.net core MVC 过滤器的执行顺序
asp.net core MVC 过滤器会在请求管道的各个阶段触发.同一阶段又可以注册多个范围的过滤器,例如Global范围,controller范围等.以ActionFilter为例,我们来看看过滤 ...
- ASP.NET Core MVC 过滤器介绍
过滤器的作用是在 Action 方法执行前或执行后做一些加工处理.使用过滤器可以避免Action方法的重复代码,例如,您可以使用异常过滤器合并异常处理的代码. 过滤器如何工作? 过滤器在 MVC Ac ...
- ASP.NET Core MVC 过滤器
参考网址:https://www.cnblogs.com/dotNETCoreSG/p/aspnetcore-4_4_3-filters.html ASP.NET Core有五种类型的过滤器,每个过滤 ...
- 扒一扒asp.net core mvc控制器的寻找流程
不太会排版,大家将就看吧. asp.net core mvc和asp.net mvc中都有一个比较有意思的而又被大家容易忽略的功能,控制器可以写在非Web程序集中,比如Web程序集:"MyW ...
- ASP.NET Core MVC 源码学习:详解 Action 的激活
前言 在 上一篇 文章中,我们已经学习了 ASP.NET Core MVC 的启动流程,那么 MVC 在启动了之后,当请求到达过来的时候,它是怎么样处理的呢? 又是怎么样把我们的请求准确的传达到我们的 ...
- ASP.NET Core MVC 源码学习:详解 Action 的匹配
前言 在 上一篇 文章中,我们已经学习了 ASP.NET Core MVC 的启动流程,那么 MVC 在启动了之后,当请求到达过来的时候,它是怎么样处理的呢? 又是怎么样把我们的请求准确的传达到我们的 ...
- Asp.Net Core MVC框架内置过滤器
第一部分.MVC框架内置过滤器 下图展示了Asp.Net Core MVC框架默认实现的过滤器的执行顺序: Authorization Filters:身份验证过滤器,处在整个过滤器通道的最顶层.对应 ...
- [ASP.NET Core MVC] 如何实现运行时动态定义Controller类型?
昨天有个朋友在微信上问我一个问题:他希望通过动态脚本的形式实现对ASP.NET Core MVC应用的扩展,比如在程序运行过程中上传一段C#脚本将其中定义的Controller类型注册到应用中,问我是 ...
- ASP.NET Core MVC 源码学习:MVC 启动流程详解
前言 在 上一篇 文章中,我们学习了 ASP.NET Core MVC 的路由模块,那么在本篇文章中,主要是对 ASP.NET Core MVC 启动流程的一个学习. ASP.NET Core 是新一 ...
- asp.net core MVC 全局过滤器之ExceptionFilter异常过滤器(一)
本系类将会讲解asp.net core MVC中的内置全局过滤器的使用,将分为以下章节 asp.net core MVC 过滤器之ExceptionFilter异常过滤器(一) asp.net cor ...
随机推荐
- openpyxl 设置单元格自动换行
解决方案 openpyxl的alignment函数中的参数:wrapText=True,就可以了 from openpyxl.styles import Alignment worksheet.cel ...
- 开源流量检测引擎Dalton安装记录
几个月之前照着官方文档安装过,一次性就成功,昨天重装了服务器再安装Dalton,怎么都安装不了 一直报错 ERROR: Service 'agent-suricata-current' failed ...
- ACl与ACL实验
ACl与ACL实验 ACL 1,ACL概述及 产生的背景 ACL: access list 访问控制列表 2,ACL应用 ACL两种应用: 应用在接口的ACL-----过滤数据包(原目ip地址,原目 ...
- AcWing 第 92 场周赛 C题 4866. 最大数量 题解
原题链接 链表 + 并查集乱搞做法: 思路 首先可以发现,想要让度数尽量大,那我们应该构造成菊花图,即下图所示: 对于每个需求,我们可以知道,如果之前他们没有连在一起,那我们一定得把他们连在一起,该过 ...
- 【解惑】介绍.net中的DataTable的AcceptChanges方法
DataTable.AcceptChanges方法是一个用于DataTable对象的方法,它将所有对DataTable进行的更改标记为已接受.这意味着所有新增.修改和删除的行都将被标记为DataRow ...
- golang1.21新特性速览
经过了半年左右的开发,golang 1.21 在今天早上正式发布了. 这个版本中有不少重要的新特性和变更,尤其是在泛型相关的代码上. 因为有不少大变动,所以建议等第一个patch版本也就是1.21.1 ...
- 搞懂 Vue3 中的各种 ref:toRef,toRefs,isRef,unref...
在 Vue3 中,有许多与响应式相关的函数,例如 toRef.toRefs.isRef.unref 等等.合理地使用这些函数可以在实际开发中大大提高效率.本文将详细介绍这些函数的用法,让我们在实际开发 ...
- 三维模型OBJ格式轻量化压缩处理的数据质量提升方法分析
三维模型OBJ格式轻量化压缩处理的数据质量提升方法分析 在三维模型的OBJ格式轻量化压缩处理过程中,除了减小文件大小和提高加载速度之外,我们也需要考虑如何提升数据质量.以下是几种常见的方法: 1.优化 ...
- 一次搞定:借助Hutool封装代码快速解决webservice调用烦恼
前言 相信很多同行哪怕学了许多主流技术,但工作上依然免不了和传统企业打交道,而这样的企业往往还在用webservice做接口交互. 本文是作者近两年和医疗行业的厂家打交道研究出来的一点调用webser ...
- 五分钟k8s实战-使用Ingress
背景 前两章中我们将应用部署到了 k8s 中,同时不同的服务之间也可以通过 service 进行调用,现在还有一个步骤就是将我们的应用暴露到公网,并提供域名的访问. 这一步类似于我们以前配置 Ngin ...