asp.net core系列 68 Filter管道过滤器
一.概述
本篇详细了解一下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管道过滤器的更多相关文章
- 【目录】asp.net core系列篇
随笔分类 - asp.net core系列篇 asp.net core系列 68 Filter管道过滤器 摘要: 一.概述 本篇详细了解一下asp.net core filters,filter叫&q ...
- 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 ...
- asp.net core 系列 8 Razor框架路由(下)
三.页面路由操作约定 接着上篇讲asp.net core 系列 7 Razor框架路由.在上篇继续第三节 "页面路由操作约定" 的最后一小节 AddPageRoute . 3.3. ...
- WPF中的常用布局 栈的实现 一个关于素数的神奇性质 C# defualt关键字默认值用法 接口通俗理解 C# Json序列化和反序列化 ASP.NET CORE系列【五】webapi整理以及RESTful风格化
WPF中的常用布局 一 写在开头1.1 写在开头微软是一家伟大的公司.评价一门技术的好坏得看具体的需求,没有哪门技术是面面俱到地好,应该抛弃对微软和微软的技术的偏见. 1.2 本文内容本文主要内容 ...
- Asp.net Core 系列之--2.ORM初探:Dapper实现MySql数据库各类操作
ChuanGoing 2019-09-10 距离上一篇近一个月时间,断断续续才把本篇码完,后面将加快进度,争取年度内把本系列基本介绍完成,同时督促本人持续学习. 本篇学习曲线: 1.初识Dapper ...
- 【asp.net core 系列】10 实战之ActionFilter
0.前言 在上一篇中,我们提到了如何创建一个UnitOfWork并通过ActionFilter设置启用.这一篇我们将简单介绍一下ActionFilter以及如何利用ActionFilter,顺便补齐一 ...
- 1.1专题介绍「深入浅出ASP.NET Core系列」
大家好,我是IT人张飞洪,专注于.NET平台十年有余. 工作之余喜欢阅读和写作,学习的内容包括数据结构/算法.网络技术.Linux系统原理.数据库技术原理,设计模式.前沿架构.微服务.容器技术等等…… ...
- asp.net core系列 30 EF管理数据库架构--必备知识 迁移
一.管理数据库架构概述 EF Core 提供两种主要方法来保持 EF Core 模型和数据库架构同步.一是以 EF Core 模型为基准,二是以数据库为基准. (1)如果希望以 EF Core 模型为 ...
- asp.net core系列 40 Web 应用MVC 介绍与详细示例
一. MVC介绍 MVC架构模式有助于实现关注点分离.视图和控制器均依赖于模型. 但是,模型既不依赖于视图,也不依赖于控制器. 这是分离的一个关键优势. 这种分离允许模型独立于可视化展示进行构建和测试 ...
随机推荐
- 图像滤镜艺术---ZPhotoEngine超级算法库
原文:图像滤镜艺术---ZPhotoEngine超级算法库 一直以来,都有个想法,想要做一个属于自己的图像算法库,这个想法,在经过了几个月的努力之后,终于诞生了,这就是ZPhotoEngine算法库. ...
- 提示要求用户名和密码-localhost
同时安装了tomcat和oracle9i后,调试jsp出现--连接到localhost 提示:位于 XDB 的服务器 localhost 要求用户名和密码,原因是端口冲突,调整如下. 机器上装了ora ...
- C#应用配置信息保存和读取
//保存信息 SystemConfig.WriteConfigData(“字段名称”, “这里是需要保存的内容”); //读取信息 SystemConfig.GetConfigData(“字段名称”, ...
- Android零基础入门第31节:几乎不用但要了解的AbsoluteLayout绝对布局
原文:Android零基础入门第31节:几乎不用但要了解的AbsoluteLayout绝对布局 前面几期基本学习了Android开发中常用的四种布局,之所以把AbsoluteLayout放在后面来学习 ...
- UWP入门(七)--SplitView详解与页面跳转
原文:UWP入门(七)--SplitView详解与页面跳转 官方文档,逼着自己用英文看,UWP开发离不开官方文档 1. SplitView 拆分视图控件 拆分视图控件具有一个可展开/可折叠的窗格和一个 ...
- 20 个免费开源的 CSS3 用户界面工具包
ui.css Metro UI CSS Pure CSS jQuery jKit Solid HTML5/CSS3 UI Kit CSS3 UI Kit Alt CSS3 UI Kit MediaLo ...
- QT Udp组播(穿透)
http://blog.csdn.net/victoryknight/article/details/7814243 主题 UDPQt路由器 局域网内的两台机器如果隔有路由器,那么这两台机器之间不 ...
- UILabel实现自适应宽高需要注意的地方(三)
一.需求图如下所示 UILabel 的高度自适应 UILabel中的段落间距可设置 图片效果如下: 调整段落适应长宽高方式: 需求: 保证"游戏玩法 ...
- sql server使用公用表表达式CTE通过递归方式编写通用函数自动生成连续数字和日期
问题:在数据库脚本开发中,有时需要生成一堆连续数字或者日期,例如yearly report就需要连续数字做年份,例如daily report就需要生成一定时间范围内的每一天日期.而自带的系统表mast ...
- Binary classification - 聊聊评价指标的那些事儿【回忆篇】
在解决分类问题的时候,可以选择的评价指标简直不要太多.但基本可以分成两2大类,我们今分别来说道说道 基于一个概率阈值判断在该阈值下预测的准确率 衡量模型整体表现(在各个阈值下)的评价指标 在说指标之前 ...