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. Tomcat的测试网页换成自己项目首页

    <Host name="localhost" appBase="webapps" unpackWARs="true" autoDepl ...

  2. 5G网络与4G相比,有什么区别?

    5G 是 2018 年移动通信领域的热词.从中兴的芯片卡脖事件,联想 5G 投票风波再到华为频遭威胁.这些事件都引起了大家对于 5G 的关注,那么 5G 到底是什么,它和 4G 有什么区别呢? 今天就 ...

  3. Linux - 通过SecureCRT的rz、sz和sftp实现文件的上传和下载

    目录 1 通过rz/sz命令上传/下载 1.1 安装lrzsz软件 1.2 rz - 上传文件 1.3 sz - 下载文件 2 通过sftp上传/下载文件 2.1 关于SFTP的简介 2.2 SFTP ...

  4. DotNetCore跨平台~EFCore废弃了TransactionScope取而代之的Context.Database.BeginTransaction

    回到目录 TransactionScope是.net平台基于的分布式事务组件,它默认为本地事务,同时当系统有需要时可以自动提升为分布式事务,而对系统的前提是要开启MSDTC服务,必要时需要在数据库服务 ...

  5. 一致性Hash漫画图解

    一年之前—— 未来两年内,系统预估的总订单数量可达一亿条左右. 按Mysql单表存储500万条记录来算,暂时不必分库,单库30个分表是比较合适的水平分表方案. 于是小灰设计了这样的分表逻辑: 订单表创 ...

  6. Js-函数式编程

    前言 JavaScript是一门多范式语言,即可使用OOP(面向对象),也可以使用FP(函数式),由于笔者最近在学习React相关的技术栈,想进一步深入了解其思想,所以学习了一些FP相关的知识点,本文 ...

  7. c# aes,des,md5加密等解密算法

    一:可逆加密,即是能加密也能解密 对称可逆加密:加密后能解密回原文,加密key和解密key是一个 加密算法都是公开的,密钥是保密的, 即使拿到密文 你是推算不了密钥 也推算不了原文 加密解密的速度快, ...

  8. 远程连接桌面报:这可能是由于credssp加密oracle修正

      1.Win+R 输入regedit打开注册表 找到对应的以下目录HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Polic ...

  9. 2015年第六届蓝桥杯javaB组 试题 答案 解析

    1.三角形面积 如图1所示.图中的所有小方格面积都是1. 那么,图中的三角形面积应该是多少呢? 请填写三角形的面积.不要填写任何多余内容或说明性文字. ##### 答案 : 28   ### 2.立方 ...

  10. html 微信video放大后无法返回问题

    android  video播放视频放大后无法返回,先debug下debugx5.qq.com 发现用的不是X5内核 直接激活  debugmm.qq.com/?forcex5=true  问题解决 ...