介绍

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的更多相关文章

  1. Asp.Net Core Filter 深入浅出的那些事-AOP

    一.前言 在分享ASP.NET Core Filter 使用之前,先来谈谈AOP,什么是AOP 呢? AOP全称Aspect Oriented Programming意为面向切面编程,也叫做面向方法编 ...

  2. ASP.NET Core Filter如何支持依赖注入

    通过Filter来支持:分别有IResourceFilter AuthorizeFilter ActionFilter ExceptionFilter ResultFilter,Filter也被称为拦 ...

  3. ASP.NET Core Filter与IOC的羁绊

    前言 我们在使用ASP.NET Core进行服务端应用开发的时候,或多或少都会涉及到使用Filter的场景.Filter简单来说是Action的拦截器,它可以在Action执行之前或者之后对请求信息进 ...

  4. Asp.net Core Filter过滤器异常处理

    本文旨在: 1 继承ExceptionFilterAttribute,重写Override OnException(ExceptionContext context)处理异常 2 在.netCore中 ...

  5. Asp.Net Core 进阶(四)—— 过滤器 Filters

    一.介绍 Asp.Net Core Filter 使得可以在请求处理管道的特定阶段的前后执行代码,我们可以创建自定义的 filter 用于处理横切关注点. 横切关注点的示例包括错误处理.缓存.配置.授 ...

  6. Asp.Net Core Endpoint 终结点路由之中间件应用

    一.概述 这篇文章主要分享Endpoint 终结点路由的中间件的应用场景及实践案例,不讲述其工作原理,如果需要了解工作原理的同学, 可以点击查看以下两篇解读文章: Asp.Net Core EndPo ...

  7. ASP.NET Core 2.2 十八.各种Filter的内部处理机制及执行顺序

    ASP.NET core 的Filter是系统中经常用到的,本文详细分享一下各种Filter定义.执行的内部机制以及执行顺序.(ASP.NET Core 系列目录) 一. 概述 ASP.NET Cor ...

  8. ASP.NET Core 中间件 中间件(Middleware)和过滤器(Filter)的区别

    https://www.cnblogs.com/savorboard/p/5586229.html 前言 在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际使用的, ...

  9. ASP.NET CORE MVC 2.0 如何在Filter中使用依赖注入来读取AppSettings,及.NET Core控制台项目中读取AppSettings

    问: ASP.NET CORE MVC 如何在Filter中使用依赖注入来读取AppSettings 答: Dependency injection is possible in filters as ...

  10. [转]Create Custom Exception Filter in ASP.NET Core

    本文转自:http://www.binaryintellect.net/articles/5df6e275-1148-45a1-a8b3-0ba2c7c9cea1.aspx In my previou ...

随机推荐

  1. 014_用vim复制粘贴_保持双手正位

    [oeasy]python0014_用vim复制粘贴_保持双手正位 继续运行 回忆上次内容 程序员 还是 很可爱的 要关心 身边的程序员 啊 毕竟是新时代的 典型新职业     文明 主流职业 血型 ...

  2. [oeasy]python0069_帮助手册_pydoc_manual_document

    帮助手册 回忆上次内容   上次了解了注释 注释是为了让程序更可读 注释不会影响程序运行速度   注释分为两种 单行的 以#开头 不能是字符串当中的#   多行的 三个" 三个'     多 ...

  3. 内存溢出+CPU占用过高:问题排查+解决方案+复盘(超详细分析教程)

    内存溢出+CPU占用过高:问题排查+解决方案+复盘(超详细分析教程) 原文地址 https://zhanghan.blog.csdn.net/article/details/109255980 前言 ...

  4. 【Oracle】Windows-19C 下载安装

    下载 Download 官网下载地址[需要Oracle账号]: https://www.oracle.com/database/technologies/oracle-database-softwar ...

  5. 【Lodop】02 C-Lodop手册阅读上手

    版本:4.0.6.2 一.概述 C-Lodop云打印是一款精巧快捷的云打印服务产品,以Lodop功能语句为基础,JS语句实现远程打印 移动设备+Wifi+普通打印机+集中打印 C-Lodop对客户端浏 ...

  6. Google主打的机器学习计算框架——jax的升级包

    相关: 机器学习洞察 | 一文带你"讲透" JAX Jax的主要应用场景: 深度学习 (Deep Learning):JAX 在深度学习场景下应用很广泛,很多团队基于 JAX 开发 ...

  7. 【转载】ubuntu22.04安装gcc-8失败

    版权声明:本文为CSDN博主「Death_Note_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/Death ...

  8. 【Azure Developer】使用Python SDK去Azure Container Instance服务的Execute命令的疑问解释

    Azure Container Instance服务介绍 Azure 容器实例(Azure Container Instances,简称 ACI)是一个无服务器容器解决方案,允许用户在 Azure 云 ...

  9. mysql读写分离之springboot集成

    springboot.mysql实现读写分离 1.首先在springcloud config中配置读写数据库 mysql: datasource: readSize: 1 #读库个数 type: co ...

  10. dubbo超时异常 荐

    dubbo超时异常 在调用dubbo服务时经常看到如下错误: Caused by: com.alibaba.dubbo.remoting.TimeoutException: Waiting serve ...