一.概述

  本篇详细了解一下asp.net core filters,filter叫"筛选器"也叫"过滤器",是请求处理管道中的特定阶段之前或之后运行代码。filter用于处理横切关注点。 横切关注点的示例包括:错误处理、缓存、配置、授权和日志记录。 filter可以避免重复代码,通过Attribute特性来实现filter过滤。Filter适应于 Razor Pages,  API controllers,  mvc controllers。filter基类是IFilterMetadata 接口,该接口只是用来标记是一个filter过滤器。

  前段时间在项目中实现了IAsyncAuthorizationFilter接口对用户访问controller或action进行了授权,在OnAuthorizationAsync方法中使用context.Result可使管道短道。IAsyncAuthorizationFilter是属于授权过滤器中的一种。勿在授权过滤器内抛出异常,这是因为所抛出的异常不会被处理。下面是简要的实现授权代码:

   [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class PermissionFilter : Attribute,IAsyncAuthorizationFilter
  {
    public Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
IIdentity user = context.HttpContext.User.Identity;
if (!user.IsAuthenticated)
     {
            //跳转到登录页
            context.Result = new LocalRedirectResult(url);
             return Task.CompletedTask;
          }         //根据当前用户,判断当前访问的action,没有权限时返回403错误
         context.Result = new ForbidResult();    return Task.CompletedTask;
     }
}

  在官方文档中说到:"自定义授权筛选器Filter需要自定义授权框架, 建议配置授权策略或编写自定义授权策略,而不是编写自定义Filter筛选器"。

  这里的意思是说,如果在项目中不使用asp.net core自带的identity,那么需要自定义授权框架,也就是需要自己建立一套用户权限表。 如果使用了identity建议配置授权策略或编写自定义授权策略。如果不用identity自己建立用户权限表,那么就可以编写自定义Filter筛选器。我在项目开发中是自己建立了用户权限表没有用identity。因为使用identity表还需要扩展字段,而且与EF core结合紧密,如果不使用EF core需要重写访问identity表的实现。

  下面是identity与ef core相关的代码: 

   services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders(); -- TContext必须是DbContext类型
public static IdentityBuilder AddEntityFrameworkStores<TContext>(this IdentityBuilder builder) where TContext : DbContext

二.Filter 筛选器类型

    Authorization filters  授权筛选器

    Resource filters       资源筛选器

    Action filters            操作筛选器 (Razor Pages 中使用 IPageFilter 和 IAsyncPageFilter)

    Exception filters      异常筛选器

    Result filters            结果筛选器

    每种Filter 类型都在Filter 管道中的不同阶段执行,当用户请求进来时,经过Filter管道,执行Filter的阶段顺序如下所示:

    上面每种Filter 类型都有自己的接口,都同时支持同步和异步实现,上面的授权示例就是一个异步实现授权筛选器IAsyncAuthorizationFilter。Filter 接口或直接或间接实现了IFilterMetadata接口,IFilterMetadata接口只是用来标记是一个Filter 。

三.filter筛选器作用域

  (1) 将 attribute特性应用在 action上。

  (2) 将 attribute特性应用在 controller上。

  (3) 全局筛选器应用在controller和action上

    下面使用全局筛选器,使用MvcOptions.Filters 集合,添加三个筛选器,如下面的代码所示:

public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.Filters.Add(new AddHeaderAttribute("GlobalAddHeader",
"Result filter added to MvcOptions.Filters")); // An instance
options.Filters.Add(typeof(MySampleActionFilter)); // By type
options.Filters.Add(new SampleGlobalActionFilter()); // An instance
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
//实现了内置筛选器属性
public class AddHeaderAttribute : ResultFilterAttribute
//实现了操作筛选器
public class MySampleActionFilter : IActionFilter
//实现了操作筛选器
public class SampleGlobalActionFilter : IActionFilter

四.内置筛选器Attribute属性

    下面都是filter内置的属性类,需要去实现这些抽象属性类。

      ActionFilterAttribute
      ExceptionFilterAttribute
      ResultFilterAttribute
      FormatFilterAttribute
      ServiceFilterAttribute
      TypeFilterAttribute

  下面一个示例是为响应添加标头,开发人员来实现ResultFilterAttribute抽象类:

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);
}
}

    通过使用属性,筛选器可接收参数,将 AddHeaderAttribute 添加到控制器或操作方法,并指定 HTTP 标头的名称和值,如下所示:

        [AddHeader("Author", "Steve Smith @ardalis")]
public IActionResult Hello(string name)
{
return Content($"Hello {name}");
}

五.Filter三种依赖关系注入

    (1)ServiceFilterAttribute
    (2)TypeFilterAttribute
    (3)在属性上实现 IFilterFactory。

  5.1 ServiceFilterAttribute演示

    下面是在 ConfigureServices 中注册服务筛选器实现类型,内置的ServiceFilterAttribute会从DI 检索筛选器实例。

public class AddHeaderResultServiceFilter : IResultFilter
{
private ILogger _logger;
public AddHeaderResultServiceFilter(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<AddHeaderResultServiceFilter>();
} public void OnResultExecuting(ResultExecutingContext context)
{
var headerName = "OnResultExecuting";
context.HttpContext.Response.Headers.Add(
headerName, new string[] { "ResultExecutingSuccessfully" });
_logger.LogInformation($"Header added: {headerName}");
} public void OnResultExecuted(ResultExecutedContext context)
{
// Can't add to headers here because response has started.
}
}

    在以下代码中,AddHeaderResultServiceFilter 将添加到 DI 容器中:

    services.AddScoped<AddHeaderResultServiceFilter>();

    在以下代码中,通过ServiceFilter 属性,将从 DI 中检索 AddHeaderResultServiceFilter 筛选器的实例:

[ServiceFilter(typeof(AddHeaderResultServiceFilter))]
public IActionResult Index()
{
return View();
}

六. 各种筛选器介绍

  6.1 Authorization filters 

    是筛选器管道中第一个运行的筛选器。是控制对Action方法的访问。

     在Action之前执行的方法,没有在Action之后执行的方法。

     注意:不要在授权筛选器中引发异常

    场景:

      如果使用identity,可用配置授权策略或编写自定义授权策略。详情查看identity部分。

      如果不使用identity,可编写自定义筛选器。

  6.2 Resource filters

    实现 IResourceFilter 或 IAsyncResourceFilter 接口。

    它执行会覆盖筛选器管道的绝大部分。

    它在授权筛选器之后运行。

    场景:

      可以防止模型绑定访问表单数据。

      用于上传大型文件,以防止表单数据被读入内存。

  6.3 Action filters

    实现 IActionFilter 或 IAsyncActionFilter 接口。

    它围绕着Action方法的执行。

    它方法中有个重要属性ActionArguments ,用于读取action的输入参数。

    场景:

      可以在该接口的OnActionExecuting方法中进行验证模型状态(ModelState.IsValid),如果状态无效,则返回错误(这个场景很有用)。

  6.4 Exception filters

    实现 IExceptionFilter 或 IAsyncExceptionFilter。

    它没有之前和之后的事件,

    可实现该接口的 OnException 或 OnExceptionAsync方法。

    处理 Razor 页面或控制器创建、模型绑定、操作筛选器或操作方法中发生的未经处理的异常。

    若要处理异常(不再throw),请将 ExceptionHandled 属性设置为 true。

    场景:

      实现常见的错误处理策略。

      非常适合捕获发生在action中的异常。

    下面是项目中的一个示例, 注意在授权器中引发的异常是无法捕获的。

    public class GlobalAsyncExceptionFilter : IAsyncExceptionFilter
{
//日志对象
public readonly ILoggerEX _logger; public GlobalAsyncExceptionFilter(ILoggerEX logger)
{
_logger = logger;
} public Task OnExceptionAsync(ExceptionContext context)
{
string errormsg = "全局捕获未处理的异常,errorMsg:" + context.Exception.Message + context.Exception.StackTrace;
_logger.Error(errormsg);
context.Result = new ObjectResult(errormsg);
       context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
//不再throw,在此捕获
context.ExceptionHandled = true;
return Task.CompletedTask;
}
}
            services.AddMvc(option=> {
option.Filters.Add(typeof(GlobalAsyncExceptionFilter));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        public CustomerController(INotificationHandler<DomainNotification> notifications,
ILoggerEX logger,
CustomerAppService customerAppService)
: base(notifications)
{
_customerAppService = customerAppService;
_logger = logger;
throw new Exception("自定义一个未捕获的异常!");
}

    当访问Customer控制器时,全局异常过滤器将会自动捕获,如下所示:

  6.5 Result filters

    实现 IResultFilter 或 IAsyncResultFilter 或 IAlwaysRunResultFilter 或 IAsyncAlwaysRunResultFilter

    它执行围绕着action结果的执行。当异常筛选器处理异常时,不执行结果筛选器。

    如果在 IResultFilter.OnResultExecuting 中引发异常,则会导致:

      (1) 阻止action结果和后续筛选器的执行。

      (2) 结果被视为失败。

  更详细的资料参考官网文档,后续在实际项目中应用到的筛选器,将会再本篇继续补上。

  参考资料:

    官方文档

    官方示例代码

asp.net core系列 68 Filter管道过滤器的更多相关文章

  1. 【目录】asp.net core系列篇

    随笔分类 - asp.net core系列篇 asp.net core系列 68 Filter管道过滤器 摘要: 一.概述 本篇详细了解一下asp.net core filters,filter叫&q ...

  2. Ajax跨域问题及解决方案 asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS) c#中的Cache缓存技术 C#中的Cookie C#串口扫描枪的简单实现 c#Socket服务器与客户端的开发(2)

    Ajax跨域问题及解决方案   目录 复现Ajax跨域问题 Ajax跨域介绍 Ajax跨域解决方案 一. 在服务端添加响应头Access-Control-Allow-Origin 二. 使用JSONP ...

  3. asp.net core 系列 8 Razor框架路由(下)

    三.页面路由操作约定 接着上篇讲asp.net core 系列 7 Razor框架路由.在上篇继续第三节 "页面路由操作约定" 的最后一小节 AddPageRoute . 3.3. ...

  4. WPF中的常用布局 栈的实现 一个关于素数的神奇性质 C# defualt关键字默认值用法 接口通俗理解 C# Json序列化和反序列化 ASP.NET CORE系列【五】webapi整理以及RESTful风格化

    WPF中的常用布局   一 写在开头1.1 写在开头微软是一家伟大的公司.评价一门技术的好坏得看具体的需求,没有哪门技术是面面俱到地好,应该抛弃对微软和微软的技术的偏见. 1.2 本文内容本文主要内容 ...

  5. Asp.net Core 系列之--2.ORM初探:Dapper实现MySql数据库各类操作

    ChuanGoing 2019-09-10 距离上一篇近一个月时间,断断续续才把本篇码完,后面将加快进度,争取年度内把本系列基本介绍完成,同时督促本人持续学习. 本篇学习曲线: 1.初识Dapper ...

  6. 【asp.net core 系列】10 实战之ActionFilter

    0.前言 在上一篇中,我们提到了如何创建一个UnitOfWork并通过ActionFilter设置启用.这一篇我们将简单介绍一下ActionFilter以及如何利用ActionFilter,顺便补齐一 ...

  7. 1.1专题介绍「深入浅出ASP.NET Core系列」

    大家好,我是IT人张飞洪,专注于.NET平台十年有余. 工作之余喜欢阅读和写作,学习的内容包括数据结构/算法.网络技术.Linux系统原理.数据库技术原理,设计模式.前沿架构.微服务.容器技术等等…… ...

  8. asp.net core系列 30 EF管理数据库架构--必备知识 迁移

    一.管理数据库架构概述 EF Core 提供两种主要方法来保持 EF Core 模型和数据库架构同步.一是以 EF Core 模型为基准,二是以数据库为基准. (1)如果希望以 EF Core 模型为 ...

  9. asp.net core系列 40 Web 应用MVC 介绍与详细示例

    一. MVC介绍 MVC架构模式有助于实现关注点分离.视图和控制器均依赖于模型. 但是,模型既不依赖于视图,也不依赖于控制器. 这是分离的一个关键优势. 这种分离允许模型独立于可视化展示进行构建和测试 ...

随机推荐

  1. python 动态调用模块&类&方法

    转载自:http://www.cnblogs.com/bluefrog/archive/2012/05/11/2496439.html 一直想知道python里有没有类似php中的 $classnam ...

  2. .NET框架中系列专业技术术语和缩写

    CIL (Common Intermediate Language) 公共中间语言 : CIL最初是随着.NET由微软一起发布的,之前也叫MSIL(Microsoft Intermediate Lan ...

  3. C#正则表达式简单案例解析

    正则表达式主要用于字符串的操作. 1.Regex.IsMatch:判断指定的字符串是否符合正则表达式. 2.Regex.Match:提取匹配的字符串,只能提取到第一个符合的字符串.这里还可以使用组来提 ...

  4. DLL中类的显式链接(用虚函数进行显式链接)

    DLL的显式链接在某些时候比隐式链接具有更大的灵活性.比如,如果在运行时发现DLL无法找到,程序可以显示一个错误信息并能继续运行.当你想为你的程序提供插件服务时,显式链接也很有用处. 显式链接到全局C ...

  5. MongoDB自学日记2——权限

    首先应该明确的是为什么要学MongoDB.OK,如果是仅仅出于对于流行技术的原始兴趣,可能并不能深入学习,还必须有应用需求.刚开始学习MongoDB,因为以前对其它数据库的了解也不是特别深入,所以许多 ...

  6. Terminator快捷键

    窗口相关 窗口开关 上下开新窗口   Ctrl+Shift+O垂直开新窗口   Ctrl+Shift+E关闭当前窗口   Ctrl+Shift+W 改变当前激活窗口 逆时针改变当前窗口 Ctrl+Sh ...

  7. Nginx学习笔记---服务与集群

    一.集群 什么是集群 服务器架构集群:多台服务器组成的响应式大并发,高数据量访问的架构体系. 特点: (1)成本高 (2)能够降低单台服务器的压力,使用流量平均分配到多台服务器 (3)使网站服务架构更 ...

  8. 关于CORS 应该注意的几点

    前言 对于跨域,随着w3c的CORS的出现,相比较于有些年头的jsonp,CORS以其简单安全,支持post的优势越来越收到大家的欢迎.具体如何CORS的原理和实现,直接推荐阮老师的文章,十分详细.本 ...

  9. MCtalk对话尚德机构:AI讲师,假套路还是真功夫?

    一间容纳百人的被挤得满满的教室,老师讲.学生听.线下课堂曾是职业教育最普遍的形式.随着移动互联网的普及,大量的学习行为逐渐转化到线上进行,传统教育机构如何抓住这轮技术转型的契机,而不是被它吞噬? 近日 ...

  10. 【React入门】React父子组件传值demo

    公司一直是前后端分离的,最近集团开始推进中后台可视化开发组件(基于React封装),跟师兄聊起来也听说最近对后台开发人员的前端能力也是越来越重视了.所以作为一名后端,了解下前端的框架对自己也是大有好处 ...