ASP .NET Core Api 使用过滤器
过滤器说明
过滤器与中间件很相似,过滤器(Filters)可在管道(pipeline)特定阶段(particular stage)前后执行操作。可以将过滤器视为拦截器(interceptors)。
过滤器级别范围
过滤器有多个级别,分别是:
- 全局级别过滤器(Global scope),通过
Program.cs全局添加Filter - 控制器级别过滤器(Controller scope),通过
AttributeUsage特性配置 - 动作级别过滤器(Action scope),通过
AttributeUsage特性配置
过滤器类型
Asp.Net Core 过滤器:
- IResourceFilter
- IAuthorizationFilter
- IPageFilter
- ExceptionFilterAttribute
- ActionFilterAttribute
| 过滤器类型 | 接口 | 对应特性 | 含义 |
|---|---|---|---|
| 授权过滤器 | IAuthorizationFilter、IAsyncAuthorizationFilter | 没有提供特性类 | 最先执行,用于判断用户是否授权。如果未授权,则直接结束当前请求。这种类型的过滤器实现了 IAsyncAuthorizationFilter 或IAuthorizationFilter 接口。 |
| 资源过滤器 | IResourceFilter、IAsyncResourceFilter | 没有提供特性类 | 在Authorization过滤器后执行,并在执行其他过滤器 (除Authorization过滤器外)之前和之后执行。由于它在Action之前执行,因而可以用来对请求判断,根据条件来决定是否继续执行Action。这种类型过滤器实现了 IAsyncResourceFilter 或 IResourceFilter 接口。 |
| 操作过滤器 | IActionFilter、IAsyncActionFilter | ActionFilterAttribute | 在Action执行的前后执行。与Resource过滤器不一样,它在模型绑定后执行。这种类型的过滤器实现了 IAsyncActionFilter 或 IActionFilter 接口。 |
| 页面过滤器 | IPageFilter、IAsyncPageFilter | 没有提供特性类 | 页面过滤器是 Razor Pages 等效的操作过滤器 |
| 结果过滤器 | IResultFilter、IAsyncResultFilter、 IAlwaysRunResultFilter、IAsyncAlwaysRunResultFilter | ResultFilterAttribute | 在 IActionResult 执行的前后执行,使用它能够控制Action的执行结果,比如:格式化结果等。需要注意的是,它只有在Action方法成功执行完成后才会运行。这种类型过滤器实现了 IAsyncResultFilter 或 IResultFilter 接口。 |
| 异常过滤器 | IExceptionFilter、IAsyncExceptionFilter | ExceptionFilterAttribute | 异常过滤器用于管理未处理的异常,比如:用于捕获异常。这种类型的过滤器实现了 IAsyncExceptionFilter 或 IExceptionFilter 接口。 |
不同类型的过滤器在ASP.NET Core中的位置。可以看到不同类型的过滤器在不同阶段起作用。授权过滤器先于其他所有操作,并在任何授权错误时阻止请求。 资源过滤器在模型验证和模型绑定请求之前运行,也在我们的请求结果从服务器返回时运行。 动作过滤器类型在动作调用之前和之后起作用。 此外,如果操作引发异常,则会触发异常过滤器。 在管道的末尾,结果过滤器对 IActionResult 最终对象实例进行操作。

ActionFilter
ActionFilterAttribute 拦截器通过 重写 OnActionExecuting,来 拦截action的请求消息,当执行OnActionExecuting完成以后才真正进入请求的action中,action运行完后又把控制权给了 OnActionExecuted,这个管道机制可以使我们用它来轻松实现 权限认证、日志记录 ,跨域以及很多需要对全局或者部分请求做手脚的的功能。
大概的流程如下:

ActionFilter全称是ActionFilterAttribute,我们根据微软的命名规范可以看出这是一个特性类,看一下它的声明:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public abstract class ActionFilterAttribute : Attribute, IActionFilter, IFilterMetadata, IAsyncActionFilter, IAsyncResultFilter, IOrderedFilter, IResultFilter
这是一个允许标注在类和方法上的特性类,允许多个标记,标注之后子类会继承父类的特性。然后,这个类是一个抽象类,所以我们可以通过继承ActionFilterAttribute来编写自己的ActionFilter。
ActionFilter 四个方法
public virtual void OnActionExecuted(ActionExecutedContext context);
public virtual void OnActionExecuting(ActionExecutingContext context);
public virtual void OnResultExecuted(ResultExecutedContext context);
public virtual void OnResultExecuting(ResultExecutingContext context);

上图是这四个方法在一次请求中执行的顺序。在一次请求真正执行之前,想要拦截这个请求,应该使用OnActionExecuting。
为什么单独说这个呢?因为这个方法的出镜率很高,大多数时候都会使用这个方法进行请求过滤。
获取Api请求相关信息
在Program.cs中添加EnableBuffering。一定要添加在UseEndpoints和MapControllers之前
//3.0
//app.Use(next => context =>
//{
// context.Request.EnableBuffering();
// return next(context);
//});//net6.0
//启动倒带方式
//app.Use(async (context, next) => {
// context.Request.EnableBuffering();
// await next();
//});app.Use((context, next) =>
{context.Request.EnableBuffering();return next(context);
});//同步需要添加此代码
builder.Services.Configure<KestrelServerOptions>(x => x.AllowSynchronousIO = true).Configure<IISServerOptions>(x => x.AllowSynchronousIO = true);
添加同步ActionFilter或异步ActionFilter。注意:同步与异步不能一起使用 同步ActionFilter
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.AspNetCore.Mvc.Controllers;
using System.Text;
using System.Text.Json;namespace WebApplication1
{[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]public class ApiFilter : ActionFilterAttribute{private string ActionArguments { get; set; }/// <summary>/// 执行方法体之前/// </summary>/// <param name="context"></param>public override void OnActionExecuting(ActionExecutingContext context){try{if (context.ActionArguments != null && context.ActionArguments.Count > 0){ActionArguments = JsonSerializer.Serialize(context.ActionArguments);}else{ActionArguments = string.Empty;}}catch (Exception ex){var _serviceProvider = context.HttpContext.RequestServices;_serviceProvider.GetService<ILogger<ApiFilter>>()!.LogError(ex.StackTrace);}base.OnActionExecuting(context);}/// <summary>/// 执行方法体之后,返回result前/// </summary>/// <param name="context"></param>public override void OnActionExecuted(ActionExecutedContext context){var request = context?.HttpContext?.Request;//获取IServiceProvidervar _serviceProvider = context.HttpContext.RequestServices;//判断Body是否存在var isBody = context.ActionDescriptor.Parameters.Any(r => r.BindingInfo?.BindingSource == BindingSource.Body);//请求地址string url = request.Host + request.Path + request.QueryString;var descriptor = (ControllerActionDescriptor)context.ActionDescriptor;//获取控制器名称var controllerName = descriptor.ControllerName;//获取action名称var actionName = descriptor.ActionName;//获取request参数var requestArguments = ActionArguments;//请求方式string method = request.Method;//请求Headervar headrs = request.Headers;//context.HttpContext.Request.Form//获取Request Bodystring requestBody = string.Empty;if (request.Method == "POST" && request.Body != null){using StreamReader sr = new StreamReader(request.Body);if (request.Body.CanSeek) request.Body.Seek(0, SeekOrigin.Begin);if (request.Body.CanRead) requestBody = sr.ReadToEnd();if (request.Body.CanSeek) request.Body.Seek(0, SeekOrigin.Begin);}//获取Response Bodyvar Response = context?.HttpContext?.Response;var result = context.Result;if (result is JsonResult json){var x = json.Value;var status = json.StatusCode;var content = JsonSerializer.Serialize(x);}if (result is ViewResult view){var status = view.StatusCode;var content = view.ViewData;var name = view.ViewName;}if (result is ObjectResult ob){var x = ob.Value;var status = ob.StatusCode;var content = JsonSerializer.Serialize(x);}base.OnActionExecuted(context);}/// <summary>/// 返回result之前/// </summary>/// <param name="context"></param>public override void OnResultExecuting(ResultExecutingContext context){base.OnResultExecuting(context);}/// <summary>/// 返回result之后/// </summary>/// <param name="context"></param>public override void OnResultExecuted(ResultExecutedContext context){base.OnResultExecuted(context);}}
}
异步ActionFilter
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Text.Json;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Net;namespace WebApplication1.Filter
{[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]public class ApiAsyncFilter : ActionFilterAttribute{public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next){//执行方法体之前//...//执行方法体await base.OnActionExecutionAsync(context, next);//执行方法体之后//获取requestBodyvar request = context?.HttpContext?.Request;string requestBody = string.Empty;if (request.Method == "POST" && request.Body != null){using StreamReader sr = new StreamReader(request.Body);if (request.Body.CanSeek) request.Body.Seek(0, SeekOrigin.Begin);if (request.Body.CanRead) requestBody = await sr.ReadToEndAsync();//第二种方法if (request.Body.CanRead){var result = await request.BodyReader.ReadAsync();requestBody = Encoding.UTF8.GetString(result.Buffer);}if (request.Body.CanSeek) request.Body.Seek(0, SeekOrigin.Begin);}}public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next){//返回result之前await base.OnResultExecutionAsync(context, next);}}
}
ActionFilter 记录异常日志
using Microsoft.AspNetCore.Mvc.Filters;
using System.Text.Json;namespace WebApplication1
{public class ExceptionFilter : ActionFilterAttribute{private string ActionArguments { get; set; }/// <summary>/// 执行方法体之后,返回result前/// </summary>/// <param name="context"></param>public override void OnActionExecuted(ActionExecutedContext context){if (context.Exception != null){LoggerError(context, context.Exception);}base.OnActionExecuted(context);}/// <summary>/// 执行方法体之前/// </summary>/// <param name="context"></param>public override void OnActionExecuting(ActionExecutingContext context){try{if (context.ActionArguments != null && context.ActionArguments.Count > 0){ActionArguments = JsonSerializer.Serialize(context.ActionArguments);}else{ActionArguments = string.Empty;}}catch (Exception ex){context.HttpContext.RequestServices.GetService<ILogger<ExceptionFilter>>()!.LogError(ex.StackTrace);}base.OnActionExecuting(context);}private void LoggerError(ActionExecutedContext context, Exception exception){var _logger = context.HttpContext.RequestServices.GetService<ILogger<ExceptionFilter>>()!;try{string url = context.HttpContext.Request.Host + context.HttpContext.Request.Path + context.HttpContext.Request.QueryString;string method = context.HttpContext.Request.Method;string message = $"\n" + $"地址:{url} \n " +$"方式:{method} \n " +$"参数:{ActionArguments}\n " +$"错误描述:{context.Exception.Message}\n " +$"错误堆栈:{context.Exception.StackTrace}\n ";if (exception.InnerException != null){message += "\n InnerException异常Message:" + exception.InnerException.Message;message += "\n InnerException异常StackTrace:" + exception.InnerException.StackTrace;}_logger.LogError(message);}catch (Exception ex){_logger.LogError(ex.StackTrace);}}}
}
ExceptionFilter 记录异常日志
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.EntityFrameworkCore;
using System;
using System.Net;
using System.Text.Json;namespace WebApplication1
{public class ExceptionFilter : ExceptionFilterAttribute{public override void OnException(ExceptionContext context){Exception ex = context.Exception;string url = context.HttpContext.Request.Host + context.HttpContext.Request.Path + context.HttpContext.Request.QueryString;string method = context.HttpContext.Request.Method;string message = $"\n " + $"地址:{url} \n " +$"方式:{method} \n " +$"错误描述:{ex.Message}\n " +$"错误堆栈:{ex.StackTrace}\n ";//while (ex.InnerException != null) { ex = ex.InnerException; }if (ex.InnerException != null){message += "\n InnerException异常Message:" + ex.InnerException.Message;message += "\n InnerException异常StackTrace:" + ex.InnerException.StackTrace;}context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;context.Result = new ObjectResult(message);// 表明异常已处理,客户端可得到正常返回context.ExceptionHandled = true;base.OnException(context);}}
}
全局添加过滤器
在Program.cs添加Filter
builder.Services.Configure<MvcOptions>(opts => opts.Filters.Add<ExceptionFilter>());builder.Services.AddControllersWithViews(options =>
{//options.Filters.Add(new ApiFilter(null,null));options.Filters.Add<ApiFilter>();
});//或者
builder.Services.Configure<MvcOptions>(opts => opts.Filters.Add<ExceptionFilter>());
参考文档
ASP.NET Core教程-Filter(过滤器)
https://www.cnblogs.com/cqpanda/p/16907950.html
全局获取异常
https://www.cnblogs.com/shenweif/p/17236321.html
相关文章:
ASP .NET Core Api 使用过滤器
过滤器说明 过滤器与中间件很相似,过滤器(Filters)可在管道(pipeline)特定阶段(particular stage)前后执行操作。可以将过滤器视为拦截器(interceptors)。 过滤器级别范围…...
CodeGPT--(Visual )
GitCode - 开发者的代码家园 gitcode.com/ inscode.csdn.net/liujiaping/java_1706242128563/edit?openFileMain.java&editTypelite marketplace.visualstudio.com/items?itemNameCSDN.csdn-codegpt&spm1018.2226.3001.9836&extra%5Butm_source%5Dvip_chatgpt_c…...
1.Mybatis入门
目录 前言 1入门 1.1 入门程序实现 1.2 数据准备 编辑 1.3 配置Mybatis 1.4 编写SQL语句 1.5 单元测试 1.6 解决SQL警告与提示 2. JDBC介绍(了解) 2.1 介绍 2.2 代码 2.3 问题分析 2.4 技术对比 3. 数据库连接池 3.1 介绍 3.2 产品 4. lombok 4.1 介绍 4.…...
android camera系列(Camera1、Camera2、CameraX)的使用以及输出的图像格式
一、Camera 1.1、结合SurfaceView实现预览 1.1.1、布局 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.com/apk/res-au…...
live555搭建流式rtsp服务器
源代码已上传gitee 一、需求 live555源代码中的liveMediaServer是将本地文件作为源文件搭建rtsp服务器,我想用live555封装一个第三方库,接收流数据搭建Rtsp服务器;预想接口如下: class LiveRtspServer { public:/***brief构造一…...
Apache孵化器领路人与导师的职责
对于捐赠到 ASF 孵化器的项目来说, ASF 孵化器项目管理委员会(IPMC)的成员会扮演两个角色,一个 孵化器领路人(Champion),另外一个是孵化器导师(Mentor)。 本文源自 ALC …...
【C++中STL】set/multiset容器
set/multiset容器 Set基本概念set构造和赋值set的大小和交换set的插入和删除set查找和统计 set和multiset的区别pair对组两种创建方式 set容器排序 Set基本概念 所有元素都会在插入时自动被排序。 set/multist容器属于关联式容器,底层结构属于二叉树。 set不允许容…...
使用 create-react-app 创建 react 应用
一、创建项目并启动 第一步:全局安装:npm install -g create-react-app 第二步:切换到想创建项目的目录,使用命令create-react-app hello-react 第三步:进入项目目录,cd hello-react 第四步:启…...
obs-studio 源码学习 obs.h
obs.h 引用头文件介绍 c99defs.h:这个头文件提供了一些 C99 标准的定义和声明,包括一些常用的宏定义和类型定义,用于提高代码的可移植性和兼容性。 bmem.h:这个头文件提供了对内存分配和管理的功能,包括一些内存分配…...
C语言-指针的基本知识(上)
一、关于内存 存储器:存储数据器件 外存 外存又叫外部存储器,长期存放数据,掉电不丢失数据 常见的外存设备:硬盘、flash、rom、u盘、光盘、磁带 内存 内存又叫内部存储器,暂时存放数据,掉电数据…...
4核16G幻兽帕鲁服务器优惠价格表,阿里云和腾讯云报价
幻兽帕鲁服务器价格多少钱?4核16G服务器Palworld官方推荐配置,阿里云4核16G服务器32元1个月、96元3个月,腾讯云幻兽帕鲁服务器服务器4核16G14M带宽66元一个月、277元3个月,8核32G22M配置115元1个月、345元3个月,16核64…...
GitHub 上传文件夹到远程仓库、再次上传修改文件、如何使用lfs上传大文件、github报错一些问题
按照大家的做法,把自己遇到的问题及解决方案写出来(注意:Error里面有些方法有时候我用可以成功,有时候我用也不能成功,写出来仅供参考,实在不行重头再clone,add,commit,p…...
一些es的基本操作
目录 给索引增加字段:给索引删除字段[^1]:创建索引:插入document删除document(应该是按ID) : 给索引增加字段: 用postMan: 给名为population_portrait_hash_seven的索引增加了一个text类型的字段。 用chrome插件Elasticvue 的Re…...
酒鬼酒2024年展望:稳发展动能,迈入恢复性增长轨道
文 | 琥珀酒研社 作者 | 渡过 最近几个月来,白酒估值回落到近十年来低位,反映出了整个白酒行业的市场低迷和虚弱现状。不管是头部企业五粮液、泸州老窖,还是区域酒企口子窖、金种子酒等,最近都通过“回购”或“增持”࿰…...
1002. HarmonyOS 开发问题:鸿蒙 OS 技术特性是什么?
1002. HarmonyOS 开发问题:鸿蒙 OS 技术特性是什么? 硬件互助,资源共享 分布式软总线 分布式软总线是多种终端设备的统一基座,为设备之间的互联互通提供了统一的分布式通信能力,能够快速发现并连接设备,高效地分发…...
vue-cli 无法安装问题解决
在macOS上安装vue-cli,但一直都失败,最后终于解决。 先后报错了2个问题。 报错无法安装 其实原因是源被切断,默认的源是官方的,但在CN是无法正常访问,各种问题。直接将源修改才可以。但可能需要试多次。 npm config…...
spring-bus消息总线的使用
文章目录 依赖bus应用接口用到的封装参数类 接收的应用监听器定义的事件类 使用bus定义bus远程调用A应用数据更新后通过bus数据同步给B应用 依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bus-amqp…...
isctf---re
crackme 解压得到crackme.exe 运行得到flag babyRe 先猜e65537的rsa 先用Z3强行求出p、q,算出常规rsa中的phi,然后套用公式求出m exp #babyre wp from z3 import * import libnum from Crypto.Util.number import * p,q,cInts(p q c) S Solver() S…...
C语言第十二弹--扫雷
✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】 扫雷 1、扫雷游戏分析和设计 1.1、扫雷游戏的功能说明 1.2 游戏的分析和设计 1.2.1、数据结构的分析 1.2.2、文件结构设计 2、扫雷游戏的结构分析 2.1、用…...
网路服务器——线程池技术
文章目录 一、线程池技术二、使用原理三、优点总结 一、线程池技术 预创建原则,线程池内部准备线程备用, 不宜过多。线程应该重用性,可以一对多处理任务或服务不同的客户端。处理单元(线程)数量并不固定,动态扩容与缩减(任务量)。…...
Unity安卓打包实战指南:从环境配置到APK生成全链路排错
1. 这不是“入门教程”,而是一份写给真实开发现场的生存指南你打开Unity,新建一个3D项目,拖进一个Cube,点击Play——它动了。你松了口气,觉得“Unity好像也没那么难”。但当你把APK打包发给测试同事,对方回…...
C语言双端队列完整实现:一行代码吃透头尾操作,算法效率拉满
一、为什么C语言实现双端队列,是数据结构的必学天花板?在C语言数据结构里,队列、栈都是基础中的基础,但真正能把灵活度、效率、内存管理三者揉到一起的,还得是双端队列(deque)。普通队列只能一头…...
BLE蓝牙扫描深度剖析:扫描原理、核心参数、前后台差异
一、前言BLE设备交互分为两大角色:广播端(外设Peripheral)与扫描端(中心Central)。上一篇博客详解了四大广播模式,本文聚焦配套核心能力——BLE扫描机制。绝大多数蓝牙开发疑难问题:前台能扫后台…...
Wechat2RSS:微信公众号转RSS订阅工具
文章目录Wechat2RSS:微信公众号转RSS订阅工具Wechat2RSS:微信公众号转RSS订阅工具 ttttmr开源的Wechat2RSS项目,目前在GitHub上获得1409颗Star,项目地址为https://github.com/ttttmr/Wechat2RSS。该工具的核心作用是将微信公众号…...
别再盲跑了!手把手教你用Arduino Zero在IDE 2.0里设置断点单步调试
告别盲跑时代:Arduino Zero与IDE 2.0的源码级调试实战指南 当你的Arduino项目逻辑越来越复杂,仅靠串口打印调试就像在迷宫里摸黑前行——直到遇见Arduino Zero与IDE 2.0的调试组合。本文将揭示如何用这套工具实现 源码级精准调试 ,即使你手…...
Redis分布式锁进阶第二十篇
一、本篇前置衔接 第二十篇我们完成了全系列终局复盘,整理了故障排查SOP与企业级落地铁律。常规单资源锁、热点分片锁、隔离锁全部讲透,但真实复杂业务永远不是单一资源:下单要扣库存、扣优惠券、扣积分、冻结余额,多资源并行争抢…...
2026智慧校园规划必读:如何在预算吃紧下选到高性价比方案
✅作者简介:合肥自友科技 📌核心产品:智慧校园平台(包括教工管理、学工管理、教务管理、考务管理、后勤管理、德育管理、资产管理、公寓管理、实习管理、就业管理、离校管理、科研平台、档案管理、学生平台等26个子平台) 。公司所有人员均有多…...
基于MaixCam的延时摄影系统:从硬件选型到Python编程全解析
1. 项目概述:用MaixCam打造你的专属延时摄影工坊延时摄影,这个听起来有点专业、甚至带点“魔法”色彩的词,其实离我们并不遥远。想想看,把一朵花从含苞到绽放的几天时间,压缩成十几秒的惊艳绽放;或者把一座…...
Airtest Poco实战:5分钟搞定微信小程序自动化测试环境搭建与元素抓取
Airtest Poco实战:5分钟搞定微信小程序自动化测试环境搭建与元素抓取微信小程序作为轻量级应用的代表,已经渗透到电商、社交、工具等各个领域。随着小程序功能的日益复杂,自动化测试成为保障产品质量的重要手段。本文将带你快速搭建微信小程序…...
CANN runtime:昇腾NPU 运行时的职责边界
个人主页:ujainu 文章目录前言为什么需要运行时这一层runtime管什么,不管什么Stream:并行的基本调度单位Event:跨Stream的同步锚点内存池化:少一次malloc就少一次卡顿任务队列:从计算图到硬件指令的最后一跳…...
