一.概述

  本篇详细了解一下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. 图像滤镜艺术---ZPhotoEngine超级算法库

    原文:图像滤镜艺术---ZPhotoEngine超级算法库 一直以来,都有个想法,想要做一个属于自己的图像算法库,这个想法,在经过了几个月的努力之后,终于诞生了,这就是ZPhotoEngine算法库. ...

  2. 提示要求用户名和密码-localhost

    同时安装了tomcat和oracle9i后,调试jsp出现--连接到localhost 提示:位于 XDB 的服务器 localhost 要求用户名和密码,原因是端口冲突,调整如下. 机器上装了ora ...

  3. C#应用配置信息保存和读取

    //保存信息 SystemConfig.WriteConfigData(“字段名称”, “这里是需要保存的内容”); //读取信息 SystemConfig.GetConfigData(“字段名称”, ...

  4. Android零基础入门第31节:几乎不用但要了解的AbsoluteLayout绝对布局

    原文:Android零基础入门第31节:几乎不用但要了解的AbsoluteLayout绝对布局 前面几期基本学习了Android开发中常用的四种布局,之所以把AbsoluteLayout放在后面来学习 ...

  5. UWP入门(七)--SplitView详解与页面跳转

    原文:UWP入门(七)--SplitView详解与页面跳转 官方文档,逼着自己用英文看,UWP开发离不开官方文档 1. SplitView 拆分视图控件 拆分视图控件具有一个可展开/可折叠的窗格和一个 ...

  6. 20 个免费开源的 CSS3 用户界面工具包

    ui.css Metro UI CSS Pure CSS jQuery jKit Solid HTML5/CSS3 UI Kit CSS3 UI Kit Alt CSS3 UI Kit MediaLo ...

  7. QT Udp组播(穿透)

      http://blog.csdn.net/victoryknight/article/details/7814243 主题 UDPQt路由器 局域网内的两台机器如果隔有路由器,那么这两台机器之间不 ...

  8. UILabel实现自适应宽高需要注意的地方(三)

        一.需求图如下所示    UILabel 的高度自适应 UILabel中的段落间距可设置   图片效果如下:   调整段落适应长宽高方式:         需求:   保证"游戏玩法 ...

  9. sql server使用公用表表达式CTE通过递归方式编写通用函数自动生成连续数字和日期

    问题:在数据库脚本开发中,有时需要生成一堆连续数字或者日期,例如yearly report就需要连续数字做年份,例如daily report就需要生成一定时间范围内的每一天日期.而自带的系统表mast ...

  10. Binary classification - 聊聊评价指标的那些事儿【回忆篇】

    在解决分类问题的时候,可以选择的评价指标简直不要太多.但基本可以分成两2大类,我们今分别来说道说道 基于一个概率阈值判断在该阈值下预测的准确率 衡量模型整体表现(在各个阈值下)的评价指标 在说指标之前 ...