一、介绍  

  Asp.Net Core Filter 使得可以在请求处理管道的特定阶段的前后执行代码,我们可以创建自定义的 filter 用于处理横切关注点。 横切关注点的示例包括错误处理、缓存、配置、授权和日志记录。 filter 使得可以避免重复代码。

  Asp.Net Core 提供了5中过滤器类型,分别是:

  1、Authorization filters,授权过滤器是最先执行并且决定请求用户是否经过授权认证,如果请求未获授权,授权过滤器可以让管道短路。

  2、Resource filters,资源过滤器在Authorization filter执行完后执行,它有两个方法,OnResourceExecuting可以在filter管道的其余阶段之前运行代码,例如可以在模型绑定之前运行。OnResourceExecuted则可以在filter管道的其余阶段之后运行代码

  3、Action filters,操作过滤器可以在调用单个操作方法之前和之后立即运行代码,它可以用于处理传入某个操作的参数以及从该操作返回的结果。 需要注意的是,Aciton filter不可以在 Razor Pages 中使用。

  4、Exception filters,异常过滤器常常被用于在向响应正文写入任何内容之前,对未经处理的异常应用全局策略。

  5、Result filters,结果过滤器可以在执行单个操作结果之前和之后运行代码。 但是只有在方法成功执行时,它才会运行。

  至于它们在filter管道中的交互方式可以看下图。

    

二、实现

  Asp.Net Core提供了同步和异步两种filter接口定义,通过实现不同的接口可以实现同步或异步的过滤器,但是如果一个类同时实现了同步和异步的接口,Asp.Net Core的filter 管道只会调用异步的方法,即异步优先。具体的做法可以参考微软官方文档 https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2

  以下是IActionFilter和IAsyncActionFilter的实现

public class MySampleActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// Do something before the action executes.
} public void OnActionExecuted(ActionExecutedContext context)
{
// Do something after the action executes.
}
} public class SampleAsyncActionFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(
ActionExecutingContext context,
ActionExecutionDelegate next)
{
// Do something before the action executes. // next() calls the action method.
var resultContext = await next();
// resultContext.Result is set.
// Do something after the action executes.
}
}

  除了直接实现Filter接口,Asp.Net Core同时提供了一些基于特性的过滤器,我们可以继承相应的特性来实现自定义的过滤器。这些特性包括ActionFilterAttributeExceptionFilterAttributeResultFilterAttributeFormatFilterAttributeServiceFilterAttributeTypeFilterAttribute

  下面是微软文档的一个例子,在Result Filter给响应添加Header。

public class AddHeaderAttribute : ResultFilterAttribute
{
private readonly string _name;
private readonly string _value; public AddHeaderAttribute(string name, string value)
{
_name = name;
_value = value;
} public override void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.Headers.Add( _name, new string[] { _value });
base.OnResultExecuting(context);
}
} [AddHeader("Author", "Joe Smith")]
public class SampleController : Controller
{
public IActionResult Index()
{
return Content("Examine the headers using the F12 developer tools.");
} [ShortCircuitingResourceFilter]
public IActionResult SomeResource()
{
return Content("Successful access to resource - header is set.");
}
}

三、Filter 的作用域和执行顺序

  可以将我们自定义的filter添加到我们的代码中进行调用,添加的方式有三种,对应其三个作用域:在Action上添加特性、在Controller上添加特性和添加全局filter。

  下面先来看下添加全局filter的做法,我们知道,在Asp.Net MVC中,filter都是在控制器实例化之后才能生效的,其Filter应该是确定的,不能被注入参数,但是到了Asp.Net Core,全局注册是在ConfigureServices方法中完成的,它可以被注入参数。

public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
}); services.AddMvc(options =>
{
options.Filters.Add(new AddHeaderAttribute("name", "Jesen"));
options.Filters.Add(typeof(AddLogActionAttribute));
options.Filters.Add(typeof(ExceptionHandlerAttribute));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

  上述代码在addMvc中将我们自定义的 filter 添加到全局当中,这样对所有的控制器和action都产生了作用。而其他两种作用域的用法就是直接将特性添加到其上面。

[AddHeader("", "")]
public class HomeController : Controller
{
[AddLogAction]
public IActionResult Index()
{
return View();
}
}

  那么这三种作用域的默认执行顺序是怎样的,下图很好的进行了展示。

  那么我们是否可以改变其默认执行顺序呢,答案当然是肯定的。我们可以通过实现 IOrderFilter来重写默认执行序列。 IOrderedFilter 公开了Order 属性来确定执行顺序,该属性优先于作用域。 具有较低的 Order 值的 filter 在具有较高的 Order 值的filter之前运行 before 代码,在具有较高的 Order 值的 filter 之后运行 after 代码。具体做法可以在使用构造函数参数时设置Order 属性。

[CustomFilter(Name = "Controller Level Attribute", Order=)]

  在改变了Order属性后的执行顺序如下图所示

四、依赖注入

  在前面添加filter事,我们在全局添加方式中知道了 filter 可以通过类型添加,也可以通过实例添加,通过实例添加,则该实例会被应用于所有的请求,按照类型添加则将激活该类型,这意味着它会为每个请求创建一个实例,依赖注入将注入所有构造函数的依赖项。

  但是如果通过特性添加到Controller或者Action上时,该 filter 不能由依赖注入提供构造函数依赖项,这是因为特性在添加时必须提供它的构造函数参数,这是由于特性的原理决定的。那是不是通过Controller或Action的特性不能有构造函数参数呢,肯定不是的,可以通过以下特性来获得依赖注入:ServiceFilterAttribute、TypeFilterAttribute和在特性上实现 IFilterFactory。

namespace FilterDemo.Filter
{
public class AddLogActionAttribute : ActionFilterAttribute
{
private readonly ILogger _logger; public AddLogActionAttribute(ILoggerFactory loggerFactory)
{
this._logger = loggerFactory.CreateLogger<AddLogActionAttribute>();
} public override void OnActionExecuting(ActionExecutingContext context)
{
string controllerName = (string)context.RouteData.Values["controller"];
string actionName = (string)context.RouteData.Values["action"]; this._logger.LogInformation($"{controllerName}的{actionName}开始执行了...")
base.OnActionExecuting(context);
} public override void OnActionExecuted(ActionExecutedContext context)
{
base.OnActionExecuted(context);
}
}
}

  上述代码我们定义了带Logger参数的AddLogActionAttribute Filter,接下来实现怎么在Controller或Action上使用,首先在Startup中添加注入

services.AddScoped<AddLogActionAttribute>();

  然后在Controller或Action上使用 ServiceFilter

[ServiceFilter(typeof(AddLogActionAttribute))]
public class HomeController : Controller

  TypeFilterAttribute与ServiceFilterAttribute类似,但不会直接从 DI 容器解析其类型。 它使用 Microsoft.Extensions.DependencyInjection.ObjectFactory 对类型进行实例化。因为不会直接从 DI 容器解析 TypeFilterAttribute 类型,所以使用 TypeFilterAttribute 引用的类型不需要注册在 DI 容器中。

 [TypeFilter(typeof(AddLogActionAttribute))]
public IActionResult Index()
{
return View();
}

五、Resource Filter  

  最后,我们来看一下Asp.Net Core不同于之前Asp.Net MVC的 ResourceFilter,在上述介绍中,我们知道了Resource Filter在Authorization Filter执行之后执行,然后才会去实例化控制器,那么Resource Filter 就比较适合用来做缓存,接下来我们自定义一个Resource Filter。

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; namespace FilterDemo.Filter
{
public class CacheResourceFilterAttribute : Attribute, IResourceFilter
{
private static readonly Dictionary<string, object> _Cache = new Dictionary<string, object>();
private string _cacheKey;
/// <summary>
/// 控制器实例化之前
/// </summary>
/// <param name="context"></param>
public void OnResourceExecuting(ResourceExecutingContext context)
{
_cacheKey = context.HttpContext.Request.Path.ToString();
if (_Cache.ContainsKey(_cacheKey))
{
var cachedValue = _Cache[_cacheKey] as ViewResult;
if (cachedValue != null)
{
context.Result = cachedValue; //设置该Result将是filter管道短路,阻止执行管道的其他阶段
}
}
} /// <summary>
/// 把请求都处理完后执行
/// </summary>
/// <param name="context"></param>
public void OnResourceExecuted(ResourceExecutedContext context)
{
if (!String.IsNullOrEmpty(_cacheKey) &&
!_Cache.ContainsKey(_cacheKey))
{
var result = context.Result as ViewResult;
if (result != null)
{
_Cache.Add(_cacheKey, result);
}
}
}
}
}

  将其添加到HomeController的Index上

[CacheResourceFilter]
[TypeFilter(typeof(AddLogActionAttribute))]
public IActionResult Index()
{
return View();
}

  运行可以发现第一次请求按照默认顺序执行,第二次请求会在Cache中查找该请求路径是否已经在Cache当中,存在则直接返回到Result,中断了请求进入管道的其他阶段。

Asp.Net Core 进阶(四)—— 过滤器 Filters的更多相关文章

  1. 小白开学Asp.Net Core 《四》

    小白开学Asp.Net Core<三>                               —— 使用AspectCore-Framework 一.AspectCore-Frame ...

  2. 你想要的都在这里,ASP.NET Core MVC四种枚举绑定方式

    前言 本节我们来讲讲在ASP.NET Core MVC又为我们提供了哪些方便,之前我们探讨过在ASP.NET MVC中下拉框绑定方式,这节我们来再来重点看看枚举绑定的方式,充分实现你所能想到的场景,满 ...

  3. ASP.NET Core MVC四种枚举绑定方式

    前言 本节我们来讲讲在ASP.NET Core MVC又为我们提供了哪些方便,之前我们探讨过在ASP.NET MVC中下拉框绑定方式,这节我们来再来重点看看枚举绑定的方式,充分实现你所能想到的场景,满 ...

  4. ASP.NET Core MVC 之过滤器(Filter)

    ASP.NET MVC 中的过滤器允许在执行管道中的特定阶段之前或之后运行代码.可以对全局,也可以对每个控制器或每个操作配置过滤器. 1.过滤器如何工作 不同的过滤器类型在管道中的不同阶段执行,因此具 ...

  5. Asp.Net Core 进阶(三)—— IServiceCollection依赖注入容器和使用Autofac替换它

    Asp.Net Core 提供了默认的依赖注入容器 IServiceCollection,它是一个轻量级的依赖注入容器,所以功能不多,只是提供了基础的一些功能,要实现AOP就有点麻烦,因此在实际工作当 ...

  6. Asp.Net Core 进阶(二) —— 集成Log4net

    Asp.Net Core 支持适用于各种内置日志记录API,同时也支持其他第三方日志记录.在我们新建项目后,在Program 文件入口调用了CreateDefaultBuilder,该操作默认将添加以 ...

  7. Asp.Net Core 进阶(一) —— 读取appsettings.json

    我们以前在Asp.Net MVC中使用 System.Configuration.ConfigurationManager 来读取web.config文件.但是Asp.Net Core MVC已经没有 ...

  8. vue从入门到进阶:过滤器filters(五)

    Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化.过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持).过滤器应该被添加在 JavaScrip ...

  9. ASP.NET core MVC动作过滤器执行顺序

    using Microsoft.AspNetCore.Mvc.Filters; using System; using System.Threading.Tasks; namespace dotnet ...

随机推荐

  1. 缓存测试分享篇:如何利用测试环境进行灰度测试缓存迁移solo

    此文已由作者王婷英授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 缓存,看到这两个字,第一反应,最近怎么又要弄缓存的改造啊,这个测试好复杂,一不不留心就踩一个线上bug.实在 ...

  2. java反射机制基础总结

    1反射机制是啥? 反射是运行中的程序检查自己和软件运行环境的能力,它可以根据它发现的进行改变.通俗的讲就是反射可以在运行时根据指定的类名获得类的信息. 2反射机制有啥用? Reflection(反射) ...

  3. ue4 fuck

    https://answers.unrealengine.com/questions/661969/uspringarmcomponent-ucameracomponent-not-identifie ...

  4. Android开发,关于aar你应该知道的

    https://yangbo.tech/2015/10/17/all-about-aar/ 背景 在软件工程中,分治是最基本的设计原理,就如同现实中的砖.瓦.钢筋.水泥一样,模块化.组件化的分工,让我 ...

  5. 洛谷P2134 百日旅行

    P2134 百日旅行 题目背景 重要的不是去哪里,而是和你在一起.——小红 对小明和小红来说,2014年7月29日是一个美好的日子.这一天是他们相识100天的纪念日. (小明:小红,感谢你2场大考时默 ...

  6. 剑指Offer的学习笔记(C#篇)-- 反转链表

    题目描述 输入一个链表,反转链表后,输出新链表的表头. 一 . 概念普及 关于线性表等相关概念请点击这里. 二 . 实现方法 目前,可以有两种方法实现该要求. 方法一:借助外部空间实现.这里可以将单链 ...

  7. ios 适配问题

    两张图解决

  8. CF 1215解题报告

    T1 偶数输出n/2 奇数输出(n-1)/2即可 T2 判断是不是回文 不是直接输出子串 是回文继续判断 如果他前(len+1)/2内没有相同 输出-1 其他的 交换不同字符,输出子串 T3 贪心+二 ...

  9. C# 操作 Excel 文件(.xls 或 .xlsx)

    在.net中,常用的操作excel文件的方式,有三种: OLE DB的形式, 第三方框架NPOI, Office组件. 总结: 通过对比,在读取大数据量的excel文件,建议用OLE DB的形式,把e ...

  10. HttpServletRequest 和 HttpServletResponse

    Servlet配置方式 全路径匹配 以 / 开始 /a /aa/bb localhost:8080/项目名称/aa/bb 路径匹配 , 前半段匹配 以 / 开始 , 但是以 * 结束 /a/* /* ...