ASP.NET Core中的过滤器/筛选器

通过使用 ASP.NET Core MVC 中的筛选器,可在请求处理管道中的特定阶段之前或之后运行代码。

注意:本主题不适用于 Razor 页面。 ASP.NET Core 2.1 及更高版本支持适用于 Razor 页面的 IPageFilter 和 IAsyncPageFilter。 有关详细信息,请参阅 Razor 页面的筛选方法

内置筛选器处理一些任务,例如:

  • 授权(防止用户访问未获授权的资源)。
  • 确保所有请求都使用 HTTPS。
  • 响应缓存(对请求管道进行短路出路,以便返回缓存的响应)。

可以创建自定义筛选器,用于处理横切关注点。过滤器可以避免在action中编写一些重复性的代码。比如异常过滤器可以合并处理异常。

筛选器的工作原理

筛选器在 MVC 操作调用管道(有时称为筛选器管道)内运行。 筛选器管道在 MVC 选择了要执行的操作(controller中的action方法)之后运行。

筛选器类型

每种筛选器类型都在筛选器管道中的不同阶段(上图中的mvc action invocation pipeline)执行。

  • 授权筛选器最先运行,用于确定是否已针对当前请求为当前用户授权。 如果请求未获授权,它们可以让管道短路。

//startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(action =>
{ action.Filters.Add<AuthorizationFilter>();
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
} //authorizationfilter:
public class AuthorizationFilter : IAsyncAuthorizationFilter
{
private readonly ILoggerFactory loggerFactory; public AuthorizationFilter(ILoggerFactory loggerFactory)
{
this.loggerFactory = loggerFactory;
}
public Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
var logger = loggerFactory.CreateLogger<AuthorizationFilter>();
logger.LogWarning($"authorization filter is executing now ,target action is :{context.ActionDescriptor.DisplayName}");
return Task.CompletedTask;
}
}

  • 资源筛选器是授权后最先处理请求的筛选器。 它们可以在筛选器管道的其余阶段运行之前以及管道的其余阶段完成之后运行代码。 出于性能方面的考虑,可以使用它们来实现缓存或以其他方式让筛选器管道短路。 它们在模型绑定之前运行,所以可以影响模型绑定。

//startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(action =>
{
action.Filters.Add<AuthorizationFilter>();
action.Filters.Add<ResourceFilter>();
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
//resourcefilter:
public class ResourceFilter : IAsyncResourceFilter
{
private readonly ILoggerFactory loggerFactory; public ResourceFilter(ILoggerFactory loggerFactory)
{
this.loggerFactory = loggerFactory;
}
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
{
var logger = loggerFactory.CreateLogger<ResourceFilter>();
logger.LogWarning($"resource filter is executing now,valueproviderfactories count:{context.ValueProviderFactories.Count}");
var executedContext = await next();
logger.LogWarning($"resource filter is executed now ,result's type is {executedContext.Result.GetType().Name}"); }
}

  • 操作筛选器可以在调用单个操作方法之前和之后立即运行代码。 它们可用于处理传入某个操作的参数以及从该操作返回的结果。

//startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(action =>
{
action.Filters.Add<ActionsFilter>();
action.Filters.Add<AuthorizationFilter>();
action.Filters.Add<ResourceFilter>();
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
//actionsfilter
public class ActionsFilter : IAsyncActionFilter
{
private readonly ILoggerFactory factory; public ActionsFilter(ILoggerFactory factory)
{
this.factory = factory;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var logger = factory.CreateLogger<ActionsFilter>();
logger.LogWarning($"action filter is executing new ,context.modelstate:{context.ModelState.IsValid}");
var executedContext = await next();
logger.LogWarning($"action filter is executed now,executedContext controller:{executedContext.Controller.ToString()}");
}
}

  • 异常筛选器用于在向响应正文写入任何内容之前,对未经处理的异常应用全局策略。

 //startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(action =>
{
action.Filters.Add<ActionsFilter>();
action.Filters.Add<AuthorizationFilter>();
action.Filters.Add<ResourceFilter>();
action.Filters.Add<ExceptionsFilter>();
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
//exceptionsfilter:
public class ExceptionsFilter : IAsyncExceptionFilter
{
private readonly ILoggerFactory loggerFactory; public ExceptionsFilter(ILoggerFactory loggerFactory)
{
this.loggerFactory = loggerFactory;
}
public Task OnExceptionAsync(ExceptionContext context)
{
var logger = loggerFactory.CreateLogger<ExceptionsFilter>();
logger.LogWarning($"some exception's happened,exception's message:{context.Exception.Message}");
context.Result=new ObjectResult(context.Exception.Message);//这个异常被处理了一下,以200正常返回。
return Task.CompletedTask;
}
}

上面的日志打印结果可以看出exception filter实在authorization filter和resource filter以及action filter之后执行的它能捕获的异常是在action执行过程中发生的异常。所以,如果在authorization filter或者resource filter中发生异常的话,它是没有办法捕获的,可以做一个测验:将authorization filter中抛出一个异常:

可以看到这个异常是被直接抛出来了,并没有被exception handler中进行处理。接着改在resource filter中抛出一个异常,看看:

同样,在resource filter中抛出的异常exception filter也是处理不了的。也就是说在筛选器管道中,处于exception筛选器执行之前而执行的代码抛出的异常,exception筛选器是处理不了的。要想捕获程序的全局异常,我觉得应该在中间件中定义对异常的捕获。这个结论还没有进行证实,有时间再讨论。

  • 结果筛选器可以在执行单个操作结果之前和之后立即运行代码。 仅当操作方法成功执行时,它们才会运行。 对于必须围绕视图或格式化程序的执行的逻辑,它们很有用。

//startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(action =>
{
action.Filters.Add<ActionsFilter>();
action.Filters.Add<AuthorizationFilter>();
action.Filters.Add<ResourceFilter>();
action.Filters.Add<ExceptionsFilter>();
action.Filters.Add<ResultFilter>();
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
//resultfilter:
public class ResultFilter : IAsyncResultFilter
{
private readonly ILoggerFactory loggerFactory; public ResultFilter(ILoggerFactory loggerFactory)
{
this.loggerFactory = loggerFactory;
}
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
var logger = loggerFactory.CreateLogger<ResultFilter>();
logger.LogWarning($"result filter is executing, context.result is :{context.Result.GetType().Name}");
var executedContext = await next();
logger.LogWarning($"result filter is executed ,context.result is {executedContext.Result.GetType().Name}");
}
}

上面的结果是action中没有抛出异常,正常执行的结果,如果在action中抛出异常:

上下对比一下会发现,result filter只会在action正常执行没有抛出异常之后才会执行。exception filter是会捕获action抛出的异常。

下图展示了这些筛选器类型在筛选器管道中的交互方式。

实现

通过不同的接口定义,筛选器同时支持同步和异步实现。例如我上面举的例子全部都是用异步的方式实现的。

可在其管道阶段之前和之后运行代码的同步筛选器定义 OnStageExecuting 方法和 OnStageExecuted 方法。 例如,在调用操作方法之前调用 OnActionExecuting,在操作方法返回之后调用 OnActionExecuted

using FiltersSample.Helper;
using Microsoft.AspNetCore.Mvc.Filters; namespace FiltersSample.Filters
{
public class SampleActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// do something before the action executes
} public void OnActionExecuted(ActionExecutedContext context)
{
// do something after the action executes
}
}
}

异步筛选器定义单一的 OnStageExecutionAsync 方法。 此方法采用 FilterTypeExecutionDelegate 委托来执行筛选器的管道阶段。 例如,ActionExecutionDelegate 调用该操作方法(如果没有下一个action filter)或下一个操作筛选器(下一个action filter),用户可以在调用它之前和之后执行代码。

可以在单个类中为多个筛选器阶段实现接口。 例如,ActionFilterAttribute 类实现 IActionFilter 和 IResultFilter,以及它们的异步等效接口。

注意:同步和异步的只需要实现一个就行,如果两个都实现了,会优先执行异步版本的。

篇幅太长,再来一片吧。

asp.net core 2.2 中的过滤器/筛选器(上)的更多相关文章

  1. asp.net core MVC 过滤器之ActionFilter过滤器(二)

    本系类将会讲解asp.net core MVC中的内置全局过滤器的使用,将分为以下章节 asp.net core MVC 过滤器之ExceptionFilter过滤器(一) asp.net core ...

  2. ASP.NET Core HTTP 管道中的那些事儿

    前言 马上2016年就要过去了,时间可是真快啊. 上次写完 Identity 系列之后,反响还不错,所以本来打算写一个 ASP.NET Core 中间件系列的,但是中间遇到了很多事情.首先是 NPOI ...

  3. ASP.NET Core 1.0 中的依赖项管理

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  4. 在ASP.NET Core 1.0中如何发送邮件

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:目前.NET Core 1.0中并没有提供SMTP相关的类库,那么要如何从ASP.NE ...

  5. ASP.NET Core 1.0 中使用 Swagger 生成文档

    github:https://github.com/domaindrivendev/Ahoy 之前文章有介绍在ASP.NET WebAPI 中使用Swagger生成文档,ASP.NET Core 1. ...

  6. 用ASP.NET Core 1.0中实现邮件发送功能

    准备将一些项目迁移到 asp.net core 先从封装类库入手,在遇到邮件发送类时发现在 asp.net core 1.0中并示提供SMTP相关类库,于是网上一搜发现了MailKit 好东西一定要试 ...

  7. 在ASP.NET Core Web API中为RESTful服务增加对HAL的支持

    HAL(Hypertext Application Language,超文本应用语言)是一种RESTful API的数据格式风格,为RESTful API的设计提供了接口规范,同时也降低了客户端与服务 ...

  8. 在ASP.NET Core 2.0中使用CookieAuthentication

    在ASP.NET Core中关于Security有两个容易混淆的概念一个是Authentication(认证),一个是Authorization(授权).而前者是确定用户是谁的过程,后者是围绕着他们允 ...

  9. 使用Http-Repl工具测试ASP.NET Core 2.2中的Web Api项目

    今天,Visual Studio中没有内置工具来测试WEB API.使用浏览器,只能测试http GET请求.您需要使用Postman,SoapUI,Fiddler或Swagger等第三方工具来执行W ...

随机推荐

  1. nginx.conf添加lua.conf配置

    1.在nginx的conf下配置lua.conf......vi lua.conf server { listen ; server_name _; location /lua { default_t ...

  2. DensityUtil【尺寸转换工具类(px、dp互相转换)】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 用于项目中dp.px.sp之间的转换以及指定缩放值下的转换. 效果图 暂不需要 代码分析 常用的方法是px2dip.dip2px: ...

  3. SpringBoot实用小技巧之动态设置SpringBoot日志级别

    有时线上问题我们用打日志的方式来观察错误或埋点参数,但由于这些日志如果都打出来会占用大量存储空间而且覆盖了一些有效信息,所以线上级别一般设置INFO,调试级别用作特殊情况下.此时如果线上想查看调试级别 ...

  4. 图解Go语言内存分配

    目录 基础概念 内存管理单元 内存管理组件 mcache mcentral mheap 内存分配流程 总结 参考资料 Go语言内置运行时(就是runtime),抛弃了传统的内存分配方式,改为自主管理. ...

  5. Virtual Box虚拟机Ubuntu18.X系统安装及Mysql基本开发配置

    Linux简介 什么是 Linux? Linux:世界上不仅只有一个 Windows 操作系统,还有 Linux.mac.Unix 等操作系统.桌面操作系统下 Windows 是霸主,而 Linux ...

  6. c#多线程总结(纯干货)

    线程基础 创建线程 static void Main(string[] args) { Thread t = new Thread(PrintNumbers); t.Start();//线程开始执行 ...

  7. SpringBoot-MongoDB 索引冲突分析及解决

    一.背景 spring-data-mongo 实现了基于 MongoDB 的 ORM-Mapping 能力, 通过一些简单的注解.Query封装以及工具类,就可以通过对象操作来实现集合.文档的增删改查 ...

  8. IO 和 NIO 的思考

    输入输出是操作系统不可或缺的一部分,大致分为两类:面向磁盘和面向网络.在 Java 中有3种 I/O 类型:BIO.NIO 和 AIO,分别是同步阻塞.同步非阻塞和异步非阻塞 I/O,这里着重描述 B ...

  9. 贝塞尔曲线控件 for .NET (EN)

    Conmajia 2012 Updated on Feb. 18, 2018 In Photoshop, there is a very powerful feature Curve Adjust, ...

  10. [MySQL] mysql的逻辑分层

    mysql逻辑分层:1.client ==>连接层 ==>服务层==>引擎层==>存储层 server2.连接层: 提供与客户端连接的服务3.服务层: 1.提供各种用户使用的接 ...