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

【.Net技术栈梳理】10-.NET Core 程序的执行

文章目录

  • 1. .NET Core 程序的执行顺序与运行过程
    • 1.1 阶段 1:构建主机(配置和服务的准备)
    • 1.2 阶段 2:运行主机(中间件管道的构建与请求处理)
  • 2. 中间件的加载与运作机制
    • 2.1 什么是中间件?
    • 2.2 如何添加和配置中间件?
    • 2.3 中间件的标准顺序(“官方配方”)
    • 2.4 中间件的运作模式:Request Delegate 和 next
    • 2.5 短路(Short-Circuiting)
    • 2.6 创建自定义中间件

理解 .NET Core 程序的执行顺序和中间件模型,是构建高效、可定制 Web 应用程序的关键。

这里将从程序的启动入口开始,详细讲解整个执行过程,并深入剖析中间件的加载和运作机制。

1. .NET Core 程序的执行顺序与运行过程

整个过程可以清晰地分为构建(Build)运行(Run) 两大阶段。

自 .NET 6 引入的“最小托管模型”使得这一过程更加简洁明了。

1.1 阶段 1:构建主机(配置和服务的准备)

一切始于 Program.cs 中的 WebApplication.CreateBuilder(args) 方法。

// Program.cs (.NET 6+)
var builder = WebApplication.CreateBuilder(args);

这行代码在背后做了大量工作:

  1. 初始化配置(Configuration):

    • 创建了一个 ConfigurationManager 对象。
    • 按照预定的顺序(后添加的源会覆盖先添加的)从各种配置源加载配置:
      • appsettings.json 和 appsettings.{Environment}.json(如 appsettings.Development.json)
      • 环境变量
      • 命令行参数
      • 用户机密(仅在开发环境)
    • 最终形成一个统一的配置根,可以通过 builder.Configuration 访问。
  2. 配置依赖注入(Dependency Injection, DI)容器:

    • 创建了一个 IServiceCollection 的实例。
    • 自动添加框架基础服务:如日志(ILogging)、配置(IConfiguration)、WebHost 环境(IWebHostEnvironment)等最核心的服务。
    • 此时,我们可以通过 builder.Services 来注册我们应用自己的服务(如 AddControllers, AddDbContext, AddScoped, AddSingleton 等)。
  3. 创建主机基础结构:

    • 配置 Kestrel Web 服务器(默认的、跨平台的高性能服务器)。
    • 配置日志记录提供程序。

此阶段的总结:WebApplicationBuilder 就像一个“总工程师”,它按照蓝图(各种配置源)准备好了所有原材料(配置)和工具(服务),并搭建好了工厂(主机)的基础设施。

1.2 阶段 2:运行主机(中间件管道的构建与请求处理)

接下来是 var app = builder.Build(); 和后续的配置。

var app = builder.Build();
  1. 构建服务容器:

    • builder.Build() 方法使用之前注册的所有服务(builder.Services)来构建最终的 IServiceProvider(即依赖注入容器)。
    • 此后,无法再注册新的服务。
  2. 配置中间件管道(Middleware Pipeline):

    • 这是最核心、最能体现执行顺序的部分。app 对象(WebApplication 类型)提供了配置请求管道的方法。
    • 管道是一个请求委托(Request Delegate) 的链表,每个委托都可以对传入的 HTTP 请求进行操作,然后选择将其传递给下一个委托,或者直接终止管道(短路)。
    • 中间件的添加顺序决定了它们的执行顺序
  3. 运行应用程序:

    • app.Run(); 启动应用程序,开始监听配置的 URL(如 http://localhost:5000 或 https://localhost:7001)。
    • Kestrel 开始接收传入的 HTTP 请求。
    • 对于每个请求,Kestrel 会将其包装成一个 HttpContext 对象(包含了 HttpRequest 和 HttpResponse),然后将这个上下文对象送入中间件管道进行处理。

2. 中间件的加载与运作机制

2.1 什么是中间件?

中间件是组装成应用程序管道来处理请求和响应的软件组件。每个中间件组件:

  • 选择是否将请求传递给管道中的下一个组件。
  • 可以在调用下一个组件之前和之后执行工作。

2.2 如何添加和配置中间件?

在 app.Build() 之后,我们使用 WebApplication 上的方法来配置管道:

  • UseMiddleware< T >() / Use(…): 添加一个自定义的中间件类或内联中间件。

  • UseRouting(): 添加路由中间件,负责将请求匹配到端点(Endpoint)。

  • UseAuthentication(): 添加认证中间件。

  • UseAuthorization(): 添加授权中间件。

  • UseEndpoints(…): 添加端点中间件,用于执行匹配到的端点(如 MapControllers, MapRazorPages)。

  • Run(…): 添加一个终止中间件(管道末端,不会调用 next)。

  • Map(…): 创建管道分支(基于路径匹配)。

2.3 中间件的标准顺序(“官方配方”)

一个典型的、功能完整的中间件管道顺序如下,其结构可以通过以下流程图清晰展示:

HTTP Request 进入
异常/错误处理中间件
(UseExceptionHandler/UseDeveloperExceptionPage)
HTTPS 重定向中间件
(UseHttpsRedirection)
静态文件中间件
(UseStaticFiles)
路由中间件
(UseRouting)
认证中间件
(UseAuthentication)
授权中间件
(UseAuthorization)
端点中间件
(UseEndpoints)
终端中间件
(Run)
返回响应

为什么顺序如此重要?

  • 异常处理必须在最外层,以捕获管道中后续任何地方抛出的异常。

  • 静态文件放在路由之前,因为对于像 css、js、image 这样的文件请求,不需要经过认证、授权等复杂逻辑,直接返回即可,性能最高。如果先进了路由,就找不到对应的 Controller 和 Action 了。

  • 认证/授权必须在路由之后、端点之前。因为路由中间件已经确定了请求要访问哪个端点(Endpoint),而授权策略([Authorize] 特性)是附加在端点(Controller/Action)上的。授权中间件需要知道目标端点是什么,才能决定应用哪种授权策略。

2.4 中间件的运作模式:Request Delegate 和 next

每个中间件本质上都是一个委托,其签名是 Task RequestDelegate(HttpContext context)。

管道中的每个中间件都可以通过调用 next(context) 将请求传递给下一个中间件。

经典的模式: “环绕” 或 “洋葱” 模型

app.Use(async (context, next) =>
{// 1. 在调用下一个中间件之前执行的逻辑 (传入请求)Log.Information("Request starting...");await context.Response.WriteAsync("First Middleware Says Hello!<br>");await next.Invoke(); // 将请求传递给管道中的下一个中间件// 2. 在下一个中间件执行完毕回来后执行的逻辑 (传出响应)Log.Information("Request finished.");await context.Response.WriteAsync("First Middleware Says Goodbye!<br>");
});app.Run(async (context) =>
{await context.Response.WriteAsync("Terminal Middleware Handled the Request!<br>");
});

对于上述管道,请求/响应的流程和输出将是

Request -> First Middleware ("Hello") -> Terminal Middleware ("Handled") -> First Middleware ("Goodbye") -> Response

2.5 短路(Short-Circuiting)

中间件可以选择不调用 next(),从而直接终止管道,处理请求并返回响应。这称为“短路”。

  • 静态文件中间件:如果请求匹配到一个物理文件(如 site.css),它会直接返回该文件并短路管道。

  • 身份认证中间件:如果请求未认证且访问的是需要认证的资源,它可以重定向到登录页或返回 401 状态码。

  • 自定义中间件:例如,一个请求日志中间件发现 404 错误,可以直接返回一个自定义的 404 页面,而无需经过后续昂贵的 MVC 路由系统。

// 一个短路示例:健康检查端点
app.Use(async (context, next) =>
{if (context.Request.Path.StartsWithSegments("/health")){context.Response.StatusCode = 200;await context.Response.WriteAsync("Healthy");return; // 短路,不调用 next}await next();
});

2.6 创建自定义中间件

方法一:约定式中间件类

public class RequestLoggerMiddleware
{private readonly RequestDelegate _next;private readonly ILogger _logger;// 约定:必须包含RequestDelegate参数和可选的后续参数public RequestLoggerMiddleware(RequestDelegate next, ILogger<RequestLoggerMiddleware> logger){_next = next;_logger = logger;}// 约定:必须叫Invoke或InvokeAsync,接收HttpContext参数public async Task InvokeAsync(HttpContext context){_logger.LogInformation("Handling request: " + context.Request.Path);await _next(context); // 调用管道中的下一个组件_logger.LogInformation("Finished handling request.");}
}// 扩展方法,用于优雅注册
public static class RequestLoggerMiddlewareExtensions
{public static IApplicationBuilder UseRequestLogger(this IApplicationBuilder builder){return builder.UseMiddleware<RequestLoggerMiddleware>();}
}// 在Program.cs中使用
app.UseRequestLogger(); // 非常简洁

方法二:实现 IMiddleware 接口

public class CustomMiddleware : IMiddleware
{public async Task InvokeAsync(HttpContext context, RequestDelegate next){// 前置逻辑await next(context); // 传递上下文// 后置逻辑}
}// 注册(需要在DI容器中注册)
builder.Services.AddTransient<CustomMiddleware>();
app.UseMiddleware<CustomMiddleware>();

总结

  1. 执行顺序:.NET Core 程序启动遵循 构建配置与服务注册 -> 构建容器与中间件管道 -> 运行监听 的清晰流程。

  2. 运行过程:每个 HTTP 请求都被包装为 HttpContext,并流经预先构建好的中间件管道。

  3. 中间件本质:是处理 HttpContext 的委托链,通过 next 串联。

  4. 核心原则顺序至关重要。中间件的添加顺序决定了它们处理请求和响应的顺序,直接影响应用的行为、性能和安全性。

  5. 设计模式:采用“洋葱模型”,请求先逐层深入,响应再逐层返回。中间件有权决定是否传递请求(短路)。

理解了这个流程和中间件模型,就能非常灵活地定制 ASP.NET Core 应用程序的行为,例如添加全局异常处理、自定义认证、日志记录、性能监控等组件,并将它们精确地插入到管道的合适位置。


文章转载自:

http://4mEplm6j.sqbrs.cn
http://3sD7JKCE.sqbrs.cn
http://bEirrShE.sqbrs.cn
http://4a5hraOu.sqbrs.cn
http://m2Te20Jl.sqbrs.cn
http://3IJD6yYB.sqbrs.cn
http://Uq6BILtD.sqbrs.cn
http://yPHtsBBx.sqbrs.cn
http://wUYyhKVr.sqbrs.cn
http://jB3UZdoT.sqbrs.cn
http://Rs5XFaio.sqbrs.cn
http://8SerisOT.sqbrs.cn
http://v7Utu5PI.sqbrs.cn
http://yu2OKmRj.sqbrs.cn
http://Oj0QElDC.sqbrs.cn
http://94j2l5kJ.sqbrs.cn
http://MBvkLzKM.sqbrs.cn
http://dEAVlKxS.sqbrs.cn
http://d6HQdicK.sqbrs.cn
http://cAnJOgqC.sqbrs.cn
http://BYVazCv5.sqbrs.cn
http://501VTpi6.sqbrs.cn
http://hatWaV3Z.sqbrs.cn
http://4YiZ8fbW.sqbrs.cn
http://6sqhSMwk.sqbrs.cn
http://C1GhYe4C.sqbrs.cn
http://r3bMwf2r.sqbrs.cn
http://XXsIncPc.sqbrs.cn
http://Ck4Nsz9g.sqbrs.cn
http://I0oxaR1P.sqbrs.cn
http://www.dtcms.com/a/379912.html

相关文章:

  • 【完整源码+数据集+部署教程】仓库物品分类检测图像分割系统源码和数据集:改进yolo11-convnextv2
  • 软件定义汽车(SDV)与区域电子电气架构(Zonal EEA)的技术革新
  • R语言:数据读取与重构、试验设计(RCB/BIB/正交/析因)、ggplot2高级绘图与统计检验(t检验/方差分析/PCA/聚类)
  • ffmpeg切割音频
  • 【论文笔记】RadarOcc: Robust 3D Occupancy Prediction with 4D Imaging Radar
  • 【Axios 教程】从入门到高级
  • 数据库重演Real Application Testing: Database Capture FAQ (Doc ID 1920275.1)
  • 一个海康相机OCR的程序
  • 蚂蚁 S19 Pro+ Hyd 191T:高效能矿机解析与性能评测
  • C++并发编程:std::thread右值形式传参解析
  • 判断子序列
  • 鸿蒙数据安全实战:从 AES 到 RSA 的加密解密全流程解析
  • Python与MiniKanren:逻辑编程的艺术与科学
  • DeviceNet 转 EtherCAT:发那科焊接机器人与倍福 CX5140 在汽车焊装线的高速数据同步通讯配置案例
  • J002 Vue+SpringBoot电影推荐可视化系统|双协同过滤推荐算法评论情感分析spark数据分析|配套文档1.34万字
  • 连续hash函数
  • 七彩喜智慧养老:用科技温暖晚年,让关爱永不掉线
  • C++微基础蓝桥杯之旅9.9-9.12
  • 一款好看的jQuery前端框架-HisUI
  • Go语言io.Copy深度解析:高效数据复制的终极指南
  • k8s-init容器学习
  • 【算法磨剑:用 C++ 思考的艺术・Dijkstra 实战】弱化版 vs 标准版模板,洛谷 P3371/P4779 双题精讲
  • Java大厂面试实录:产业互联网大数据与AI服务场景下的微服务与智能搜索(含详细解读)
  • 苍穹外卖项目笔记day08
  • 智能逗猫球方案MCU控制方案浅析-智能宠物玩具,宠物解闷神器
  • Unity键盘控制角色运动
  • 大数据毕业设计-基于Spark的全国高速公路实时路况融合与拥堵预测系统(高分计算机毕业设计选题·定制开发·真正大数据)
  • zmq源码分析之session
  • Xcode 上传 ipa 全流程详解 App Store 上架流程、uni-app 生成 ipa 文件上传与审核指南
  • Java 泛型详解:从基础到高级应用