C# Web开发教程(八)中间件

news/2025/10/23 11:18:33/文章来源:https://www.cnblogs.com/qinganning/p/19160060

中间件

- 广义: ASP.NETCore中的中间件指ASP.NETCore中的一个组件。- 组成部分: 中间件由前逻辑、next、后逻辑3部分组成,前逻辑为第一段要执行的逻辑代码、next为指向下一个中间件的调用、   后逻辑为从下一个中间件执行返回所执行的逻辑代码。每个HTTP请求都要经历一系列中间件的处理,每个中间件对于请求进行特   定的处理后,再转到下一个中间件,最终的业务逻辑代码执行完成后,响应的内容也会按照处理的相反顺序进行处理,然后形成   HTTP响应报文返回给客户端。- 中间件组成一个管道,整个ASP.NETCore的执行过程就是HTTP请求和响应按照中间件组装的顺序在中间件之间流转的过程。开发人员可以对组成管道的中间件按照需要进行自由组合。
  • 中间件的三个概念: Map,Use,Run
- Map用来定义一个管道可以处理哪些请求
- Use和Run用来定义管道,一个管道由若干个Use和一个Run组成,每个Use引入一个中间件,而Run是用来执行最终的核心应用逻辑。
  • 我们创建一个空asp.net项目,从一无所有开始搭建中间件
// Program.cs(很简单的代码,跑起来只有一个Hello World!)var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();app.MapGet("/", () => "Hello World!");app.Run();- 运行: https://localhost:7118/- 我们可以小改一下,返回简单字符
......
app.MapGet("/", () => "Hello World!");
app.MapGet("/test", () => "你若xxxx");
......
  • 来一个简单示例
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();app.MapGet("/", () => "Hello World!");
//app.MapGet("/test", () => "你若xxxx");app.Map("/test", async (pipeBuilder) =>
{pipeBuilder.Use(async (context, next) =>{context.Response.ContentType = "text/html";await context.Response.WriteAsync("1 start<br/>");await next.Invoke();await context.Response.WriteAsync("1 end<br/>");});pipeBuilder.Use(async (context, next) =>{await context.Response.WriteAsync("2 start<br/>");await next.Invoke();await context.Response.WriteAsync("2 end<br/>");});pipeBuilder.Use(async (context, next) =>{await context.Response.WriteAsync("3 start<br/>");await next.Invoke();await context.Response.WriteAsync("3 end<br/>");});pipeBuilder.Run(async context =>{await context.Response.WriteAsync("Run<br/>");});});app.Run();

自定义中间件管道(重点)

app.Map("/test", async (pipeBuilder) =>
{// 创建自定义的中间件管道
});

中间件管道详细解析

管道执行顺序:

请求 → 中间件1 → 中间件2 → 中间件3 → Run终端 → 中间件3 → 中间件2 → 中间件1 → 响应

三个中间件的执行流程:

pipeBuilder.Use(async (context, next) =>
{context.Response.ContentType = "text/html";await context.Response.WriteAsync("1 start<br/>");  // 1. 进入时执行await next.Invoke();                                // 2. 调用下一个中间件await context.Response.WriteAsync("1 end<br/>");    // 7. 返回时执行
});pipeBuilder.Use(async (context, next) =>
{await context.Response.WriteAsync("2 start<br/>");  // 3. 进入时执行await next.Invoke();                                // 4. 调用下一个中间件await context.Response.WriteAsync("2 end<br/>");    // 6. 返回时执行
});pipeBuilder.Use(async (context, next) =>
{await context.Response.WriteAsync("3 start<br/>");  // 5. 进入时执行await next.Invoke();                                // 调用Run(没有下一个中间件)await context.Response.WriteAsync("3 end<br/>");    
});

终端中间件

pipeBuilder.Run(async context =>
{await context.Response.WriteAsync("Run<br/>");      // 5.5 执行并终止管道
});

实际输出结果

访问 /test 路径时,浏览器会显示:

1 start
2 start
3 start
Run
3 end
2 end
1 end

关键概念说明

  1. Use() - 添加中间件,可以调用下一个中间件
  2. Run() - 终端中间件,终止管道传递
  3. next.Invoke() - 调用管道中的下一个中间件
  4. 洋葱模型 - 中间件的执行顺序:进入时正序,返回时逆序

这个示例很好地展示了ASP.NET Core中间件管道的执行原理和"洋葱模型"的工作方式。

  • 注意事项: 此时若执行Run()以后,依然运行pipeBuilder.Use是不会生效了

    • 通俗理解,相当于已经return了,那么return后面再写语句,肯定是不会执行的
    ......pipeBuilder.Run(async context =>{await context.Response.WriteAsync("Run<br/>");});// 不会执行pipeBuilder.Use(async (context, next) =>{await context.Response.WriteAsync("4 start<br/>");await next.Invoke();await context.Response.WriteAsync("4 end<br/>");});
    

简单的自定义中间件

  • 如果中间件的代码比较复杂,或者我们需要重复使用一个中间件的话,我们最好把中间件的代码放到一个单独的“中间件类”中。
- 中间件类是一个普通的.NET类,它不需要继承任何父类或者实现任何接口,但是这个类需要有一个构造方法,构造方法至少要有   一个RequestDelegate类型的参数,这个参数用来指向下一个中间件。这个类还需要定义一个名字为Invoke或InvokeAsync的   方法,方法至少有一个HttpContext类型的参数,方法的返回值必须是Task类型。中间件类的构造方法和lnvoke(或           lnvokeAsync)方法还可以定义其他参数,其他参数的值会通过依赖注入自动赋值。
// Test1Middleware.csnamespace WebApplicationAboutMiddleWare
{public class Test1Middleware{private readonly RequestDelegate next;public Test1Middleware(RequestDelegate next){this.next = next;}public async Task InvokeAsync(HttpContext context){await context.Response.WriteAsync("I'm in Test1Middleware: start...<br/>");await next.Invoke(context);await context.Response.WriteAsync("I'm in Test1Middleware: end...<br/>");}}
}// Program.cs......
app.Map("/test", async (pipeBuilder) =>
{pipeBuilder.Use(async (context, next) =>{context.Response.ContentType = "text/html";await context.Response.WriteAsync("1 start<br/>");await next.Invoke();await context.Response.WriteAsync("1 end<br/>");});pipeBuilder.Use(async (context, next) =>{await context.Response.WriteAsync("2 start<br/>");await next.Invoke();await context.Response.WriteAsync("2 end<br/>");});pipeBuilder.Use(async (context, next) =>{await context.Response.WriteAsync("3 start<br/>");await next.Invoke();await context.Response.WriteAsync("3 end<br/>");});// 应用pipeBuilder.UseMiddleware<Test1Middleware>();pipeBuilder.Run(async context =>{await context.Response.WriteAsync("Run<br/>");});});app.Run();- 测试: https://localhost:7118/test,返回结果1 start
2 start
3 start
I'm in Test1Middleware: start...
Run
I'm in Test1Middleware: end...
3 end
2 end
1 end

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

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

相关文章

2025年10月朝阳门美食酒店推荐榜:福宫领衔五强对比评测

朝阳门地铁口每天涌出大量商旅与本地客流,他们或要在半小时内敲定合同,或想在周末给远道而来的亲友一顿“有排面”的聚餐。时间紧、选择多、预算差异大,是这片区域最常见的痛点:有人需要步行五分钟就能到的包间,有…

自动化组件库AdvLibSuite.CCUnified发布

什么是自动化组件库? 自动化组件库是封装好的设备控件。它包含了用于PLC的控制组件和用于上位机的视图组件。控制组件和视图组件通过UDT类型交换数据。自动化组件库可以使你的PLC-HMI编程像搭积木那样拖拽搭配。使传统…

WPF开发库推荐

NHotkey.Wpf WPF的全局快捷键功能,可以使用NHotkey.Wpf。 安装 Install-Package NHotkey.Wpf网址 https://github.com/thomaslevesque/NHotkey 示例代码 HotkeyManager.Current.AddOrReplace("SwitchWindow"…

自我成长 - 木易

《人生箴言》凡我所失,皆非我所有。凡我所求,皆受其所困。万物皆为我所用,而非我所属。大道至简,无欲则刚。无为则无所不为。世人痛苦的根源从来不是失去,而是错把拥有当成了生命的全部,人生最大的牢笼从来不是外…

10.23 Session、Cookie、Token的核心区别;Cookie和缓存(Cache)的区别

Session、Cookie、Token 的核心区别三者均用于身份认证与状态保持,核心区别在于存储位置、安全性和应用场景。 维度 Cookie Session Token 存储位置 客户端(浏览器本地文件/内存) 服务器端(内存/数据库/缓存) 客户…

DeepSeek OCR:10倍文档压缩,97%准确率,让你的 LLM 读得更快、更省

长文档上下文受限、API Token 成本居高不下、复杂版式难识别,是每个 AI 应用落地都要面对的现实问题。DeepSeek OCR 以“视觉 Token 压缩”为核心,把1000字的文档压缩到约100个视觉 Token,在保持高精度的同时显著降…

如果时间不够,无法进行充分的测试怎么办?

把有限时间聚焦在高风险高价值的测试点上,用精准测试替代全面测试大家好,我是陈哥。 最近,看到后台有读者问: 时间紧张导致测试不充分,这是一个高频难题。不少团队遇到这种情况时,要么盲目压缩测试范围导致核心问…

MyEMS 核心功能拆解:数据采集、能耗分析、智能调控如何落地?

在 “双碳” 目标与企业降本需求的双重驱动下,能源管理系统(EMS)已从 “可选配置” 变为工业、商业建筑、园区等领域的 “刚需工具”。MyEMS(My Energy Management System,定制化能源管理系统)作为聚焦 “场景化…

批量跑脚本后自定义消息内容发送至钉钉--批量跑脚本

from playwright.sync_api import sync_playwrightfrom case.baidu import mainfrom case.baidu01 import calculatefrom case.baidu02 import main01# 2. 用列表管理模块信息(只引用已导入的函数)# 格式:(函数名, …

有了 MCP,为啥 Claude 还要推出 Skills?一文带你搞懂它到底强在哪? MCP 有啥区别、该怎么用!

关注 霍格沃兹测试学院公众号,回复「资料」, 领取人工智能测试开发技术合集 最近 AI 圈又被 Claude 刷屏了。 没错,这次的主角是——Skills(技能包)。 不少人刚学会用 MCP(Model Context Protocol),结果 Claude…

香港高防服务器本地清洗与国际清洗的区别 - 实践

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

赋能未来测试英才:“测吧”一站式实训平台,为高校软件测试教学按下“加速键”

关注 霍格沃兹测试学院公众号,回复「资料」, 领取人工智能测试开发技术合集 从理论到实战,从课堂到职场,我们为您和您的学生铺就一条坚实的成才之路 尊敬的院校领导、老师们: 在软件定义世界的今天,软件质量已成为…

​FAQ: 如何在 WPF 项目中强制指定统一输出目录并确保 VS 调试正常? - 教程

​FAQ: 如何在 WPF 项目中强制指定统一输出目录并确保 VS 调试正常? - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-fami…

10 23

11.3考虑要以 \(x\) 为端需要的操作次数为 \(n - 3\) - 以 \(x\) 为端的个数 考虑方案数如果有 \((x,p),(x,q),(p,q)\) 那一定存在一个 \(r\) 有 \((p,r),(q,r)\) 则可以把 \((p,q)\) 变成 \((x,r)\) 将所有对角线写成…

2025 年锚固剂生产厂家最新推荐排行榜:锚杆 / 矿用 / 树脂锚固剂实力企业深度解析

引言 锚固剂作为煤矿、隧道等地下工程支护体系的核心材料,其性能直接决定施工安全与工程寿命。当前行业面临多重挑战:部分产品存在固化速度波动、锚固强度不足等问题,难以适配复杂地质条件;原材料价格震荡下,性价…

2025年10月中国宝宝辅食品牌推荐榜:妈妈口碑对比榜

辅食添加期是宝宝从纯乳类过渡到家庭饮食的关键窗口,家长普遍面临“吃什么、怎么吃、吃多少”的三重焦虑。国家卫健委2024年发布的《婴幼儿喂养与营养指南》指出,6—24月龄婴幼儿对铁、锌、DHA的需求较出生时增长3—…

小白指南(六)——在线安装minio存储系统(Linux版通用)

一、验证网络在线 进入Linux命令行操作界面,分别运行以下操作:ping -c 4 www.baidu.com curl -I https://www.baidu.com如果命令输出包含以下任意一行,即证明Linux服务器可以连通互联网:4 packets transmitted, 4 …

Kubernetes(K8S)中command和args区别

使用方法参考下图:Image Entrypoint Image Cmd Container command Container args Command run [/ep-1] [foo bar] <not set> <not set> [ep-1 foo bar] [/ep-1] [foo bar] …

2063. 所有子字符串中的元音

2063. 所有子字符串中的元音 https://leetcode.cn/problems/vowels-of-all-substrings/description/ 题目: 给你一个字符串 word ,返回 word 的所有子字符串中 元音的总数 ,元音是指 a、e、i、o 和 u 。 子字符串 是…

扩展域并查集

听起来玄乎,其实比较朴素的东西。 扩展域并查集是用来处理染色判定问题的一种工具。具体来说,对于一些问题,我们可能需要将一个图划分为一些不交的点集,然后保证这些点集内部的点之间没有互相连边。 一个典型的例子…