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、用…...

网路服务器——线程池技术
文章目录 一、线程池技术二、使用原理三、优点总结 一、线程池技术 预创建原则,线程池内部准备线程备用, 不宜过多。线程应该重用性,可以一对多处理任务或服务不同的客户端。处理单元(线程)数量并不固定,动态扩容与缩减(任务量)。…...

探索设计模式的魅力:深入了解适配器模式-优雅地解决接口不匹配问题
设计模式专栏:http://t.csdnimg.cn/nolNS 目录 一、引言 1. 概述 2. 为什么需要适配器模式 3. 本文的目的和结构 二、简价 1. 适配器模式的定义和特点 定义 特点 2. 适配器模式的作用和适用场景 作用 适用场景 3. 适配器模式与其他设计模式的比较 三、适配…...

matlab窗函数-hann窗和hamming窗函数
窗函数的作用 在时域上,窗函数可以看作是对原始信号进行截断或调制的加权函数。这些窗函数通常在时域上是有限的宽度,并且具有对称性,如矩形窗、汉宁窗、汉明窗和布莱克曼窗等。例如,汉明窗是一种对称窗函数,它可以用…...

Java项目实战--瑞吉外卖DAY03
目录 P22新增员工_编写全局异常处理器 P23新增员工_完善全局异常处理器并测试 p24新增员工_小结 P27员工分页查询_代码开发1 P28员工分页查询_代码开发2 P22新增员工_编写全局异常处理器 在COMMON新增全局异常捕获的类,其实就是代理我们这些controlle。通过aop把…...
docker 里使用vcs 2018 verdi等eda 图形界面
书接上文。之前借用别人的docker,使用EDA工具,苦于没有图形界面。如果只是编码,编译可能问题不大,但是如果要看波形之类的,就没法实现了。 docker 使用 vcs/2018 Verdi等 eda 软件-CSDN博客https://blog.csdn.net/guy…...

OpenHarmony—不支持解构赋值
规则:arkts-no-destruct-assignment 级别:错误 ArkTS不支持解构赋值。可使用其他替代方法,例如,使用临时变量。 TypeScript let [one, two] [1, 2]; // 此处需要分号 [one, two] [two, one];let head, tail [head, ...tail]…...

让AI帮你说话--GPT-SoVITS教程
有时候我们在录制视频的时候,由于周边环境嘈杂或者录音设备问题需要后期配音,这样就比较麻烦。一个比较直观的想法就是能不能将写好的视频脚本直接转换成我们的声音,让AI帮我们完成配音呢?在语音合成领域已经有很多这类工作了&…...

线性回归需要满足的几个假设
线性回归模型是基于一些假设构建的,这些假设有助于确保模型的有效性和可解释性。以下是线性回归需要满足的几个主要假设: 线性关系假设(Linearity): 线性回归假设因变量(目标变量)与自变量(特征…...

go语言(十八)---- goroutine
一、goroutine package mainimport ("fmt""time" )func main() {//用go创建承载一个形参为空,返回值为空的一个函数go func() {defer fmt.Println("A.defer")func() {defer fmt.Println("B.defer")//退出当前goroutinefmt…...

城市开发区视频系统建设方案:打造视频基座、加强图像数据治理
一、背景需求 随着城市建设的步伐日益加快,开发区已经成为了我国工业化、城镇化和对外开放的重要载体。自贸区、开发区和产业园的管理工作自然也变得至关重要。在城市经开区的展览展示馆、进出口商品展示交易中心等地,数千路监控摄像头遍布各角落&#…...

宏景eHRSmsAcceptGSTXServle存在XXE漏洞
指纹特征 app"HJSOFT-HCM"漏洞复现 POST /servlet/sms/SmsAcceptGSTXServlet HTTP/1.1 Host: User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36 Content-Length: 137 Content…...