当前位置: 首页 > news >正文

解构引擎——依赖注入(DI)与中间件管道

、前言:从“作坊”到“工厂”

在上一篇文章中,我们学会了C#的现代语法,就像掌握了制造精密零件的技术。现在,我们需要把这些零件组装成一台能运转的发动机。

在ASP.NET Core中,有两样东西构成了这台发动机的骨架:依赖注入(DI)中间件

如果你不理解它们,你写的代码可能会变成紧紧缠绕的一团乱麻(我们称之为“面条代码”),难以测试、难以修改。理解了它们,你就掌握了现代Web开发的“设计模式之钥”。

二、灵魂机制:依赖注入(DI)

2.1 为什么要“注入”?——解决紧耦合

假设你需要在一个API中记录日志。最直观的写法可能是直接在代码里new一个对象:

app.MapGet("/bad", () => { var logger = new FileLogger(); // 直接依赖具体的实现类 logger.Log("这是一条日志"); return "日志已记录"; });

这种写法看似简单,实则隐患重重:

  1. 紧耦合:你的API代码死死地绑定了FileLogger。如果哪天老板说“改成存数据库”,你得修改每一处new FileLogger()
  2. 难以测试:做单元测试时,你不想真的去写文件,想用一个假的记录器,但现在你无法替换。

依赖注入的核心思想是:“不要自己new,需要什么向容器要”(控制反转,IoC)。

2.2 服务的三生三世:生命周期

在.NET的DI容器中,注册的服务有三种主要生命周期。这是新手最容易踩坑的地方,请务必理解:

  1. Transient(瞬态)用完即弃。每次请求该服务,容器都会给你一个全新的实例。适合轻量级、无状态的服务(如简单的计算器、格式化工具)。
  2. Scoped(范围)一次请求一生。在一次HTTP请求范围内,无论你在多少个地方请求它,拿到的都是同一个实例。这是Web开发中最常用的模式,特别是用于数据库上下文(DbContext)
  3. Singleton(单例)万世一系。整个应用程序生命周期内,只存在一个实例。适合全局缓存、全局配置。注意:单例服务必须是线程安全的!

2.3 实战:构建一个性能监控服务

我们来写一个真实的案例:统计API的执行耗时。

第一步:定义契约(接口)良好的架构总是面向接口编程。

// IPerformanceTracker.cs public interface IPerformanceTracker { void Start(); void Stop(); long GetElapsedTime(); }

第二步:实现服务

// PerformanceTracker.cs public class PerformanceTracker : IPerformanceTracker { private Stopwatch _stopwatch = new Stopwatch(); public void Start() => _stopwatch.Restart(); public void Stop() => _stopwatch.Stop(); public long GetElapsedTime() => _stopwatch.ElapsedMilliseconds; }

第三步:在Program.cs中注册服务

var builder = WebApplication.CreateBuilder(args); // --- 注册服务 --- // 这里我们使用 Scoped,因为耗时统计通常是针对单个请求的 builder.Services.AddScoped<IPerformanceTracker, PerformanceTracker>(); // 添加Swagger等基础服务 builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); // ... 中间件配置 ...

第四步:在API中注入并使用在Minimal API中,我们通过方法参数注入服务。

app.MapGet("/test-performance", (IPerformanceTracker tracker) => { tracker.Start(); // 模拟耗时操作 Thread.Sleep(500); tracker.Stop(); return $"接口执行耗时: {tracker.GetElapsedTime()} ms"; });

架构师视角的深意: 注意看,我们的API代码里完全没有new PerformanceTracker()。这意味着,如果明天我们需要升级监控逻辑(比如加上日志记录),我们只需要修改PerformanceTracker.cs类,而API接口的代码一行都不用动。这就是解耦带来的维护性提升。

三、传动装置:中间件管道

如果说DI是提供动力的气缸,那么中间件就是负责传递动力的齿轮和传送带。

3.1 管道模型:俄罗斯套娃

ASP.NET Core 处理HTTP请求的方式,就像水流通过一系列过滤层。

  1. 请求进入管道。
  2. 经过一个个中间件。
  3. 中间件可以在处理做事(如记录请求日志)。
  4. 中间件调用next()将请求传给下一个中间件。
  5. 到达最终处理逻辑(你的API代码)。
  6. 响应沿着管道反向流出。
  7. 中间件可以在处理做事(如记录响应日志、处理异常)。

3.2 编写你的第一个自定义中间件

我们来写一个最简单的中间件:请求计时器。它将在控制台打印每个请求的耗时。

var app = builder.Build(); // --- 自定义中间件 --- app.Use(async (context, next) => { var stopwatch = new Stopwatch(); stopwatch.Start(); Console.WriteLine($"[中间件] 请求开始: {context.Request.Path}"); // 关键步骤:调用下一个中间件 // 这里使用 await 等待后续管道全部执行完毕 await next(context); stopwatch.Stop(); Console.WriteLine($"[中间件] 请求结束: {context.Request.Path}, 耗时: {stopwatch.ElapsedMilliseconds}ms"); }); // 确保有Swagger中间件 if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.MapGet("/", () => "Hello World!"); app.Run();

运行这段代码,并在浏览器访问http://localhost:5000/,你会看到控制台输出了耗时信息。

3.3 “短路”机制:权限守门员

中间件有一个极其重要的能力:短路。如果中间件决定不调用next(),管道就会直接折返,后续的逻辑(如你的API代码)将不会执行。

这非常适合做权限验证。

app.Use(async (context, next) => { // 模拟:检查Header里是否有密码 if (!context.Request.Headers.ContainsKey("X-Secret-Key")) { // 没有密钥,直接返回401,不调用 next() context.Response.StatusCode = 401; await context.Response.WriteAsync("抱歉,
http://www.cnnetsun.cn/news/3013711.html

相关文章:

  • 串联、并联电阻计算方法
  • 测试硬盘的瑞士军刀-fio
  • 企业智能表格的机会点在哪?2026 选型与落地实测指南
  • 中小工厂如何选型?从锟铭智能看设备数据采集关键维度
  • 除醛喷剂除甲醛的效果、使用频率与用量全解析
  • CTF源码解题
  • 2026年AI辅助编程深度实践:从代码生成到架构设计的全流程提效指南
  • 主流 3D 视觉三大技术路线,机器人、机器狗、机械臂、数据采集设备该怎么选?
  • 掌上高考——高校数据爬取+数据可视化
  • 免费版视频去除水印工具推荐:从桌面到手机,一套可操作的素材清理路径
  • Fastjson反序列化漏洞实战解析:从原理、利用到防御
  • MySQL性能怎么看?mysqld_exporter采集、告警与远程监控指南
  • 从零构建在线评测系统:Docker沙箱、Celery异步与安全设计实践
  • 大气层整合包系统深度解析:Nintendo Switch定制固件的架构设计与实战技巧
  • 浏阳儿童烟花品牌推荐
  • ALK-PEG-PAA / Alkyne-PEG-PAA炔基-聚乙二醇-b-聚丙烯酸二嵌段共聚物Alkyne-PEG-block-Poly(acrylic acid)
  • 51-C01-人走灯灭+AD采集+自动+手动+10档调节+坐姿监测+蜂鸣器+OLED屏+(无线方式选择)-2(设计源文件+万字报告+讲解)(支持资料、图片参考_降重降ai)
  • 自动化测试面试实战:Selenium与Cypress核心原理与工程实践
  • STM32-S266-TDS水质检测+红外感应+水量监测+保温常温+温度+灯光指示+定时提醒+定时开关+加热+防干烧+参数+OLED屏+声光提醒+(无线方式选择)-2(设计源文件+万字报告+讲解)(支
  • 堆码测试介绍及包装运输验证堆码标准选择
  • 基于51/STM32单片机智能水杯保温杯恒温温度控制防干烧水质设计STM32-S264-水量监测+保温常温+温度+灯光指示+定时提醒+定时开关+加热+防干烧+参数可设+OLED屏+声光提醒+(无线方式
  • 使用 `<Teleport>` 实现全局模态框(Vue 3)
  • 高仕星维生素B能稳固发根吗
  • 数字孪生+大模型重塑工业产线管控模式
  • Java计算机毕设之基于SpringBoot+Vue的校园潮流音乐在线播放平台设计与实现(完整前后端代码+说明文档+LW,调试定制等)
  • 【课程设计/毕业设计】基于SpringBoot的在线潮流音乐视听服务系统设计与实现 个性化歌单创建与潮流音乐播放系统设计与实现【附源码、数据库、万字文档】
  • PHP开发者的福音!这套开源商城源码,堪称二开界的“瑞士军刀”!
  • Windows、Android、iOS 各自的伟大之处
  • 【计算机毕业设计案例】基于 SpringBoot+Vue 的财务报表生成管理系统设计与实现 中小企业财会业务信息化管理系统设计与实现(程序+文档+讲解+定制)
  • IntelliJ IDEA旗舰版安装失败诊断手册(93%用户卡在第4步!含JetBrains License Server 2024.1.3实测绕过方案)