自定义中间件进入管道中执行队列的流程

news/2025/9/26 15:06:43/文章来源:https://www.cnblogs.com/zhiwu/p/19113528

自定义中间件进入管道中执行队列的流程

1. 自定义中间件类的标准写法

public class CustomLoggingMiddleware
{private readonly RequestDelegate _next;// 1. 构造函数必须包含 RequestDelegate next 参数public CustomLoggingMiddleware(RequestDelegate next){_next = next;}// 2. 必须包含名为 Invoke 或 InvokeAsync 的公共方法public async Task InvokeAsync(HttpContext context){//执行前动作...// 调用管道中的下一个中间件await _next(context);       //执行后动作...}
}

2. 使用扩展方法注册中间件

public static class CustomLoggingMiddlewareExtensions
{public static IApplicationBuilder UseCustomLogging(this IApplicationBuilder app){return app.UseMiddleware<CustomLoggingMiddleware>();}
}

3. 在管道中使用

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{app.UseCustomLogging();  // 我们的自定义中间件app.UseHttpsRedirection();app.UseStaticFiles();app.UseRouting();app.UseAuthorization();app.MapControllers();
}

4. 转换流程详解

现在来看 UseMiddleware<CustomLoggingMiddleware>() 是如何将类转换成管道方法的:

步骤 1: UseMiddleware<T> 扩展方法
// Microsoft.AspNetCore.Builder.UseMiddlewareExtensions
public static class UseMiddlewareExtensions
{public static IApplicationBuilder UseMiddleware<TMiddleware>(this IApplicationBuilder app){return app.UseMiddleware(typeof(TMiddleware));}public static IApplicationBuilder UseMiddleware(this IApplicationBuilder app, Type middlewareType){// 创建中间件工厂return app.Use(next =>{// 这里就是转换的关键!// 创建一个委托,它会在每次请求时实例化中间件并调用Invoke方法var middlewareFactory = (IMiddlewareFactory)app.ApplicationServices.GetService(typeof(IMiddlewareFactory));return async context =>{// 每次请求都会执行这个委托var middleware = middlewareFactory.Create(middlewareType);try{// 调用中间件的InvokeAsync方法await middleware.InvokeAsync(context, next);}finally{middlewareFactory.Release(middleware);}};});}
}
步骤 2: 运行时实际生成的委托

实际上,ASP.NET Core 使用更高效的代码生成机制。简化后的等效代码:

// 运行时生成的委托大致如下:
Func<RequestDelegate, RequestDelegate> generatedMiddleware = next =>
{return async context =>{// 创建中间件实例var middleware = new CustomLoggingMiddleware(next, logger);// 调用InvokeAsync方法await middleware.InvokeAsync(context);};
};
步骤 3: 管道构建过程
// 初始管道终点
RequestDelegate pipelineEnd = async context => 
{context.Response.StatusCode = 404; // 默认404
};// 应用我们的自定义中间件
var customMiddleware = generatedMiddleware(pipelineEnd);// 最终生成的委托
RequestDelegate finalPipeline = async context =>
{var logger = // 获取logger实例;var middlewareInstance = new CustomLoggingMiddleware(pipelineEnd, logger);await middlewareInstance.InvokeAsync(context);
};
完整的转换流程图示
自定义中间件类↓
UseMiddleware<T>() 扩展方法↓
反射分析中间件类的构造函数和方法↓
生成优化的委托代码 (Func<RequestDelegate, RequestDelegate>)↓
注册到 IApplicationBuilder 的中间件列表↓
管道构建时被包装成最终的 RequestDelegate↓
请求到达时执行生成的委托代码

支持多种方法签名的中间件

ASP.NET Core 支持多种方法签名,转换器会智能处理:

方式 1: 标准的 InvokeAsync 方法

csharp

public async Task InvokeAsync(HttpContext context)
{await _next(context);
}

方式 2: 带服务的 InvokeAsync 方法

csharp

public async Task InvokeAsync(HttpContext context, ISomeService service)
{// 依赖注入会自动注入服务await _next(context);
}

方式 3: 同步的 Invoke 方法

csharp

public void Invoke(HttpContext context)
{// 同步处理_next(context).Wait();
}

实际的复杂中间件示例

csharp

public class RateLimitingMiddleware
{private readonly RequestDelegate _next;private readonly IMemoryCache _cache;private readonly RateLimitOptions _options;// 构造函数注入public RateLimitingMiddleware(RequestDelegate next, IMemoryCache cache, IOptions<RateLimitOptions> options){_next = next;_cache = cache;_options = options.Value;}// 方法参数注入public async Task InvokeAsync(HttpContext context, ILogger<RateLimitingMiddleware> logger){var clientIp = context.Connection.RemoteIpAddress?.ToString();var cacheKey = $"rate_limit_{clientIp}";// 速率限制逻辑if (_cache.TryGetValue(cacheKey, out int requestCount) && requestCount >= _options.MaxRequests){logger.LogWarning("IP {IP} 触发速率限制", clientIp);context.Response.StatusCode = 429;await context.Response.WriteAsync("Too Many Requests");return;}// 更新计数器_cache.Set(cacheKey, requestCount + 1, TimeSpan.FromMinutes(1));await _next(context);}
}public class RateLimitOptions
{public int MaxRequests { get; set; } = 100;
}

依赖注入的自动处理

转换过程中,依赖注入容器会自动处理:

csharp

// 转换器会分析构造函数和方法参数
public async Task InvokeAsync(HttpContext context, ILogger<RateLimitingMiddleware> logger,        // 方法参数注入IMemoryCache cache,                            // 方法参数注入  IOptions<RateLimitOptions> options)            // 方法参数注入
{// 所有这些参数都会从DI容器自动解析
}

10. 总结:转换流程的关键步骤

  1. 类定义:创建带有 RequestDelegate 参数构造函数和 Invoke/InvokeAsync 方法的类
  2. 扩展方法注册:通过 UseMiddleware<T> 注册到管道
  3. 反射分析:框架分析中间件类的构造函数和方法签名
  4. 委托生成:生成优化的 Func<RequestDelegate, RequestDelegate> 委托
  5. 管道构建:在 Build() 方法中被包装到管道中
  6. 请求执行:每次请求时创建中间件实例并调用相应方法

这种设计的好处:

  • 类型安全:编译时检查中间件签名
  • 依赖注入:自动处理服务生命周期
  • 性能优化:使用代码生成而非纯反射
  • 灵活性:支持多种方法签名和参数注入方式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/918430.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站推广的常用途径有哪些网站ftp需要关闭

一、集成测试和系统测试的区别 &#xff08;一&#xff09;测试的目的 • 集成测试&#xff1a;主要目的是验证各个模块组合在一起后&#xff0c;它们之间的接口和交互是否正确&#xff0c;是否能够按照设计要求协同工作&#xff0c;以确保系统的稳定性和可靠性&#xff0c;重…

做一个回收网站怎么做免费网站建

当人用眼睛看事物的时候&#xff0c;会感觉到近处的东西是比远处的东西要大一些的&#xff0c;通俗的说&#xff0c;这就是透视。 总的来说。透视变换是将3D的世界转换到2D图像上的一种手段&#xff0c;人的视觉系统和摄像头视觉系统也是基于这一工作原理。 对透视变化的研究&a…

ps做产品的网站怎么做免费的产品图片网站

大家好&#xff0c;今天来聊聊论文降重隐藏字符怎么识别&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff0c;可以借助此类工具&#xff1a; 论文降重隐藏字符的识别方法 一、引言 在论文降重过程中&#xff…

翻斗幼儿园历险记-CTF-WP

翻斗幼儿园历险记 一、搭建: docker-compose up -d 运行那个docker-compose.yml文件即可打开127.0.0.1:32777就运行好了2、打法 文件上传前端过滤,bp抓包改后缀即可盲猜一波,上传的目录是/uploads下面 哥斯拉连上马…

.net8+winform+Antdui 制作 LOL 小助手

.net8+winform+Antdui 制作 LOL 小助手 .net8+winform+Antdui 制作 LOL 小助手 一、事件起因 二、筹备工作 三、查看效果 四、后期拓展想法 一、事件起因 本人 lol 菜鸡一枚,最近天天玩排位模式,有时候自己分路有优势…

深入解析:【Git】Git 简介及基本操作

深入解析:【Git】Git 简介及基本操作pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Mona…

hutool主要内容list

Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅 Hutool = Hu + tool,是原公司项目底层代码剥离后的开源库,“Hu”是公司名称的表示,too…

做图赚钱的网站有哪些中国能源建设集团有限公司是央企

QDomDocument类代表了一个XML文件 QDomDocument类代表整个的XML文件。概念上讲&#xff1a;它是文档树的根节点&#xff0c;并提供了文档数据的基本访问方法。由于元素、文本节点、注释、指令执行等等不可能脱离一个文档的上下文&#xff0c;所以文档类也包含了需要用来创建这些…

Kurt-Blender零基础教程:第2章:建模篇——第3节:陈列/父子级/蒙皮/置换修改器与小狐狸角色建模 - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

网站建设的目标客户分析建做网站

使用 Yelp 数据集进行用户画像&#xff08;User Profiling&#xff09;是一项有趣的任务&#xff0c;可以理解用户的偏好、行为和特征。以下是总结的一个基本的步骤&#xff0c;帮助构建用户画像 pandas 加载数据&#xff1a; import pandas as pd# 加载数据 users pd.read_…

中职示范校建设专题网站如何建微网站

根本原因分析中的5WHY分析法是从下列哪几个层面实施的&#xff1f; A. 制造角度 B. 检验角度 C. 体系角度 D. 以上都是 数据分析认证考试介绍&#xff1a;点击进入 题目来源于CDA模拟题库 点击此处获取答案

20250916_QQ_Powershell

流量分析, 应急响应, WebShell, Powshell, XORTags:流量分析,应急响应,WebShell,Powshell,XOR 0x00. 题目 找出受攻击主机回连的IP地址和端口号 附件路径:https://pan.baidu.com/s/1GyH7kitkMYywGC9YJeQLJA?pwd=Zmxh…

完整教程:HTTP安全响应头--CSP(Content-Security-Policy)

完整教程:HTTP安全响应头--CSP(Content-Security-Policy)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Conso…

学习:uniapp全栈微信小程序vue3后台(26) - 指南

学习:uniapp全栈微信小程序vue3后台(26) - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas"…

HTML5介绍(HTML5特性、HTML5功能) - 指南

HTML5介绍(HTML5特性、HTML5功能) - 指南2025-09-26 14:50 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: blo…

Experiment1

Experiment 1 实验任务1 1.1 #include <stdio.h> int main() {printf(" O \n");printf("<H>\n");printf("I I\n");printf(" O \n");printf("<H>\n&qu…

读书笔记:Oracle 自动索引:让数据库自己管索引?

我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢! 由于博客中有大量代码,通过页面浏览效果更佳。本文为个人学…

海安县建设局网站先备案还是先做网站

分类目录&#xff1a;《系统学习Python》总目录 文章《系统学习Python——装饰器&#xff1a;“私有“和“公有“属性案例-[实现私有属性]》中的代码有点复杂&#xff0c;并且你最好自己跟踪运行它&#xff0c;看看它是如何工作的。然而为了帮助你理解&#xff0c;这里给出一些…

1_2025.9.26_1

题目:[https://codeforces.com/problemset/problem/2140/E1] ac代码:[https://codeforces.com/contest/2140/submission/340570458] 思路:状压dp,因m<=2,n<=20,所以将状态压缩遍历,再根据题解给的式子写即…

故障处理:Oracle RAC集群CTSS时钟同步故障案例分析与解决

我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢! 由于博客中有大量代码,通过页面浏览效果更佳。本案例来自一…