尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

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

C# Web开发教程(八)中间件
📅 发布时间:2026/6/19 18:23:38

中间件

- 广义: 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

相关新闻

  • 自我成长 - 木易
  • DeepSeek OCR:10倍文档压缩,97%准确率,让你的 LLM 读得更快、更省
  • 如果时间不够,无法进行充分的测试怎么办?

最新新闻

  • LaTeX长表格排版进阶:如何用longtable宏包实现跨页表格的精细控制?
  • 2026亲测:专业降AIGC软件选它准没错 - 降AI小能手
  • LeagueAkari:基于LCU API的英雄联盟客户端工具包实现多数据源整合架构设计
  • 2026防晒墨镜哪些品牌排名高?TOP5清单出炉 - 速递信息
  • 上海汽车音响改装选哪家?上海音乐人生,二十年赛事级连锁标杆门店 - 音乐人生汽车音响
  • 技术解析:从Tri-Plane到3D GAN,如何实现高效且一致的神经渲染

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号