重新整理 .net core 实践篇——— filter[四十四]
前言
简单介绍一下filter
正文
filter 的种类,微软文档中写道:
每种筛选器类型都在筛选器管道中的不同阶段执行:
授权筛选器最先运行,用于确定是否已针对请求为用户授权。 如果请求未获授权,授权筛选器可以让管道短路。
资源筛选器:授权后运行。
OnResourceExecuting 在筛选器管道的其余阶段之前运行代码。 例如,OnResourceExecuting 在模型绑定之前运行代码。
OnResourceExecuted 在管道的其余阶段完成之后运行代码。
操作筛选器:
在调用操作方法之前和之后立即运行代码。
可以更改传递到操作中的参数。
可以更改从操作返回的结果。
Pages 中 Razor 不支持 。
异常筛选器在向响应正文写入任何内容之前,对未经处理的异常应用全局策略。
结果筛选器在执行操作结果之前和之后立即运行代码。 仅当操作方法成功执行时,它们才会运行。 对于必须围绕视图或格式化程序的执行的逻辑,它们很有用。
交互方式:

一般我们每个项目(单体或者微服务)都会用到授权筛选器和异常筛选器。
授权筛选器 是因为我们要保证用户访问的资源是其能够访问的。
异常筛选器 一般处理一些未捕获的异常进行处理,当然现在为了代码的简洁性性,一般我们在代码里面一般情况下不进行try catch。
如果是某段代码是已知的异常,比如说知道某个参数不符合规则,那么会主动抛出自定义的异常,然后在异常筛选器统一处理。
举个例子:
如果我们要进行错误码处理。
那么代码中会直接抛出。
throw CustomException("errorCode");
然后再在异常筛选器中:
if(Exception is CustomException customException)
{
// 进行错误码处理 获取其错误message
}
当然我们也可以使用异常处理中间件:
public class CustomExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;
private readonly CustomExceptionHandlerOptions _options;
public CustomExceptionHandlerMiddleware(RequestDelegate next, IOptions<CustomExceptionHandlerOptions> options)
{
_next = next;
_options = options.Value;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (System.Exception ex)
{
var logger = context.RequestServices.GetRequiredService<ILoggerFactory>()
.CreateLogger<CustomExceptionHandlerMiddleware>();
if (context.RequestAborted.IsCancellationRequested && (ex is TaskCanceledException || ex is OperationCanceledException))
{
_options.OnRequestAborted?.Invoke(context, logger);
}
else
{
_options.OnException?.Invoke(context, logger, ex);
}
}
}
}
异常处理中间件的好处也是不言而喻的,公司封装自己的异常中间件,那么每个服务使用该中间件处理方式会得到统一风格的log,且处理方式相同,那么各服务的整体风格也差不多。
这些想必非常多的开发都是比较熟悉的,然后在网关中一般会使用结果筛选器。
如果我们需要加入一个参数是requestId进行追踪的话,方便查询日志的话,那么可以这样:
public class AddRequestIdResultServiceFilter : IResultFilter
{
private ILogger _logger;
public AddRequestIdResultServiceFilter(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<AddRequestIdResultServiceFilter>();
}
public void OnResultExecuting(ResultExecutingContext context)
{
if (context.Result is ObjectResult objectResult)
{
if (objectResult.Value is DtoBaseModel dtoModel)
{
dtoModel.RequestId = context.HttpContext.TraceIdentifier;
}
}else if (context.Result is EmptyResult emptyResult)
{
context.Result = new ObjectResult(new DtoBaseModel{RequestId = context.HttpContext.TraceIdentifier });
}
}
public void OnResultExecuted(ResultExecutedContext context)
{
// Can't add to headers here because response has started.
_logger.LogInformation("AddRequestIdResultServiceFilter.OnResultExecuted");
}
}
当然这里并不是真正的requestId,而是日志追踪的id,而是TraceId。
一般会在网关中增加一个requestId是为了日志查询相关的,一般仅在网关中添加这个requestId,因为一般会做分布式追踪,也就是说网关后面的访问链的traceId都会一样,这个后面单独总结一下。
仅当操作或操作筛选器生成操作结果时,才会执行结果筛选器。 不会在以下情况下执行结果筛选器:
授权筛选器或资源筛选器使管道短路。
异常筛选器通过生成操作结果来处理异常。
Microsoft.AspNetCore.Mvc.Filters.IResultFilter.OnResultExecuting 方法可以将 Microsoft.AspNetCore.Mvc.Filters.ResultExecutingContext.Cancel 设置为 true,使操作结果和后续结果筛选器的执行短路。
设置短路时写入响应对象,以免生成空响应。 如果在 IResultFilter.OnResultExecuting 中引发异常,则会导致:
阻止操作结果和后续筛选器的执行。
结果被视为失败而不是成功。
有一个值得注意的地方:
当 Microsoft.AspNetCore.Mvc.Filters.IResultFilter.OnResultExecuted 方法运行时,响应可能已发送到客户端。 如果响应已发送到客户端,则无法更改。
如果操作结果执行已被另一个筛选器设置短路,则 ResultExecutedContext.Canceled 设置为 true。
如果操作结果或后续结果筛选器引发了异常,则 ResultExecutedContext.Exception 设置为非 NULL 值。
将 Exception 设置为 NULL 可有效地处理异常,并防止在管道的后续阶段引发该异常。 处理结果筛选器中出现的异常时,没有可靠的方法来将数据写入响应。 如果在操作结果引发异常时标头已刷新到客户端,则没有任何可靠的机制可用于发送失败代码。
对于 IAsyncResultFilter,通过调用 ResultExecutionDelegate 上的 await next 可执行所有后续结果筛选器和操作结果。 若要短路,请设置为 ResultExecutingContext.Cancel true ,不调用 ResultExecutionDelegate :
public class MyAsyncResponseFilter : IAsyncResultFilter
{
public async Task OnResultExecutionAsync(ResultExecutingContext context,
ResultExecutionDelegate next)
{
if (!(context.Result is EmptyResult))
{
await next();
}
else
{
context.Cancel = true;
}
}
}
操作筛选器
实现 IActionFilter 或 IAsyncActionFilter 接口。
它们的执行围绕着操作方法的执行。
public class MySampleActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// Do something before the action executes.
MyDebug.Write(MethodBase.GetCurrentMethod(), context.HttpContext.Request.Path);
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Do something after the action executes.
MyDebug.Write(MethodBase.GetCurrentMethod(), context.HttpContext.Request.Path);
}
}
ActionExecutingContext 提供以下属性:
ActionArguments - 用于读取操作方法的输入。
Controller - 用于处理控制器实例。
Result - 设置 Result 会使操作方法和后续操作筛选器的执行短路。
在操作方法中引发异常:
防止运行后续筛选器。
与设置 Result 不同,结果被视为失败而不是成功。
例子:
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext
context)
{
if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(
context.ModelState);
}
}
public override void OnActionExecuted(ActionExecutedContext
context)
{
var result = context.Result;
// Do something with Result.
if (context.Canceled == true)
{
// Action execution was short-circuited by another filter.
}
if(context.Exception != null)
{
// Exception thrown by action or action filter.
// Set to null to handle the exception.
context.Exception = null;
}
base.OnActionExecuted(context);
}
}
这个一般记录用户的访问情况居多,比如说全局注册,统计action的访问次数等。
资源筛选器
资源筛选器:
实现 IResourceFilter 或 IAsyncResourceFilter 接口。
执行会覆盖筛选器管道的绝大部分。
只有 授权筛选器 才会在资源筛选器之前运行。
如果要使大部分管道短路,资源筛选器会很有用。 例如,如果缓存命中,则缓存筛选器可以绕开管道的其余阶段。
资源筛选器示例:
之前显示的短路资源筛选器。
DisableFormValueModelBindingAttribute:
可以防止模型绑定访问表单数据。
用于上传大型文件,以防止表单数据被读入内存。
如:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext context)
{
var formValueProviderFactory = context.ValueProviderFactories
.OfType<FormValueProviderFactory>()
.FirstOrDefault();
if (formValueProviderFactory != null)
{
context.ValueProviderFactories.Remove(formValueProviderFactory);
}
var jqueryFormValueProviderFactory = context.ValueProviderFactories
.OfType<JQueryFormValueProviderFactory>()
.FirstOrDefault();
if (jqueryFormValueProviderFactory != null)
{
context.ValueProviderFactories.Remove(jqueryFormValueProviderFactory);
}
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
}
}
结
下一节简单整理一下分布式日志链。
重新整理 .net core 实践篇——— filter[四十四]的更多相关文章
- 重新整理 .net core 实践篇—————文件系统[二十二]
前言 简单介绍一下文件系统. 正文 文件系统,主要是下面3个接口组成: IFileProvider IFileInfo IDirectoryContents 那么他们的实现是: physicalFil ...
- 重新整理 .net core 实践篇—————HttpClientFactory[三十二]
前言 简单整理一下HttpClientFactory . 正文 这个HttpFactory 主要有下面的功能: 管理内部HttpMessageHandler 的生命周期,灵活应对资源问题和DNS刷新问 ...
- 重新整理 .net core 实践篇————网关[三十六]
前言 简单整理一下网关. 正文 在介绍网关之前,介绍一下BFF,BFF全称是Backend For Frontend,它负责认证授权,服务聚合,目标是为前端提供服务. 说的通透一点,就是有没有见过这种 ...
- 重新整理 .net core 实践篇————跨域问题四十一]
前言 简单整理一下.net core 的跨域问题,这个以前也整理过比较详细的,故而在此简单整理一下. 正文 对跨域相对的就是同源,什么是同源呢? 协议相同(http/https) 主机(域名)相同 端 ...
- 重新整理 .net core 实践篇————配置应用[一]
前言 本来想整理到<<重新整理.net core 计1400篇>>里面去,但是后来一想,整理 .net core 实践篇 是偏于实践,故而分开. 因为是重新整理,那么就从配置开 ...
- NeHe OpenGL教程 第四十四课:3D光晕
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- 孤荷凌寒自学python第四十四天Python操作 数据库之准备工作
孤荷凌寒自学python第四十四天Python操作数据库之准备工作 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 今天非常激动地开始接触Python的数据库操作的学习了,数据库是系统化设计 ...
- 网站开发进阶(四十四)input type="submit" 和"button"的区别
网站开发进阶(四十四)input type="submit" 和"button"的区别 在一个页面上画一个按钮,有四种办法: 这就是一个按钮.如果你不写ja ...
- Gradle 1.12用户指南翻译——第四十四章. 分发插件
本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
随机推荐
- dedecms编辑器不能复制word格式的处理方法
在word文档中编辑一篇文章,格式段落都整理好后,粘贴到dede编辑器里面却发现,格式都无效了,可能dede有自己的打算,比如这样可以文章字体大小统一,样色统一,整体比较整洁.但是用惯了word编辑文 ...
- GUI自动化测试遇到的问题
学习接口自动化测试框架或工具,UI自动化测试框架或工具,有时会觉得知识似乎比较零散,死记硬背不是一个好方法.一个学习的思路是思考使用这些框架或工具的时候,可能会遇到什么问题,遇到这些问题可以通过什么方 ...
- centos查找大文件
首先到相当的目录下面,按下面方式查找 find . -type f -size +800M -print0 | xargs -0 ls -lah或者从根目录(/)开始查找find / -type f ...
- vm中安装win2012并安装hyper-V不支持嵌套
在虚拟机中安装win2012,并安装hyper-v提示: 无法安装hyper-v:虚拟机监控程序已经在运行 找到虚拟机目录下,用文本编辑器打开该系统的虚拟机配置文件(.vmx后缀),在配置文件末尾增加 ...
- P2179-[NOI2012]骑行川藏【导数,二分】
正题 题目链接:https://www.luogu.com.cn/problem/P2179 题目大意 给出\(E\)和\(n\)个\(s_i,k_i,u_i\)求一个序列\(v_i\)满足 \[\s ...
- Windows 11 正式版 Build 22000.194 官方简体中文版、英文版(消费者版、商业版)下载
昨天阿三正式发布了 Windows 11,版本号竟然是 22000.194,也就是 9 月 16 日的 测试版 22000.194,仅仅是文件改了个名,特别是消费者版本 hash 校验都是一致的. W ...
- MySQL强人“锁”难《死磕MySQL系列 三》
系列文章 一.原来一条select语句在MySQL是这样执行的<死磕MySQL系列 一> 二.一生挚友redo log.binlog<死磕MySQL系列 二> 前言 最近数据库 ...
- 10.10 Rewrite 实战
将baidu.com跳转到www.baidu.com server { listen 80; server_name baidu.com; rewrite ^/ http://www.baidu.co ...
- Centos7最小安装后快速初始化脚本
功能说明 服务器通常使用最小化安装操作系统,使用该脚本可快速初始化一些基本配置,包括以下: 1.ssh修改默认端口 2.ssh禁止root登陆 3.selinux及firewalld禁用 4.hist ...
- docker初探和基础搭建
个人博客 docker中文手册 Docker 是什么? docker是一个开源的软件部署解决方案: docker也是轻量级的应用容器框架: docker可以打包.发布.运行任何的应用. 在我的粗浅理解 ...