.NET 8 中 Program.cs
的标准结构详解
一个典型的 .NET 8 Web 应用 Program.cs
看起来像这样:
// .NET 8 Program.cs - Minimal API 风格
var builder = WebApplication.CreateBuilder(args);
// 1. 配置服务 (依赖注入 DI Container)
// --------------------------------
builder.Services.AddControllers(); // 添加 MVC 控制器服务(如果使用)
builder.Services.AddEndpointsApiExplorer(); // 添加 API Explorer 服务(通常用于 Swagger)
builder.Services.AddSwaggerGen(); // 添加 Swagger 生成器服务
builder.Services.AddScoped<IMyService, MyService>(); // 注册自定义服务
// ... 其他服务注册 (数据库上下文、身份认证、授权、缓存等)
// 2. 构建应用程序实例
// --------------------------------
var app = builder.Build();
// 3. 配置中间件管道 (HTTP Request Pipeline)
// --------------------------------
if (app.Environment.IsDevelopment())
{
app.UseSwagger(); // 开发环境:提供 Swagger JSON 端点
app.UseSwaggerUI(); // 开发环境:提供 Swagger UI 界面
}
app.UseHttpsRedirection(); // 将 HTTP 请求重定向到 HTTPS
app.UseAuthorization(); // 启用授权中间件
// app.UseAuthentication(); // 如果需要认证,通常放在 UseAuthorization 前面
// app.UseStaticFiles(); // 启用静态文件服务
// app.UseRouting(); // 在 Minimal API 中通常隐式包含,显式调用也可
// 4. 配置端点 (路由)
// --------------------------------
// 方式 A: 使用 Minimal API 直接定义端点
app.MapGet("/", () => "Hello World from Minimal API!"); // GET /
app.MapGet("/api/users", (IMyService service) => service.GetUsers()); // GET /api/users,演示依赖注入
app.MapPost("/api/users", (User user) => Results.Created($"/api/users/{user.Id}", user)); // POST /api/users
// 方式 B: 使用控制器 (如果添加了 AddControllers)
app.MapControllers(); // 映射所有用 [ApiController] 和 [Route] 等属性标记的控制器
// 5. 运行应用程序
// --------------------------------
app.Run(); // 启动应用程序并开始监听请求
关键组成部分详解
-
var builder = WebApplication.CreateBuilder(args);
- 这是入口点。它创建了一个
WebApplicationBuilder
实例。 args
接收命令行参数。builder
对象是配置的起点,它提供了:Configuration
:访问appsettings.json
、环境变量、命令行参数等配置源。Services
(IServiceCollection
):用于注册应用程序所需的所有服务(依赖注入)。这是替代传统Startup.ConfigureServices
的地方。Logging
:配置日志记录提供程序。Host
/WebHost
:配置主机设置(较少需要手动配置)。
- 这是入口点。它创建了一个
-
服务注册 (
builder.Services.AddXxx()
)- 使用
builder.Services
这个IServiceCollection
来添加应用程序所需的服务。 - 常见的服务注册方法:
AddControllers()
/AddControllersWithViews()
:注册 MVC 控制器服务(如果你选择使用 Controller 而不是纯 Minimal API 端点)。AddEndpointsApiExplorer()
:为 Minimal API 或 Web API 添加 API 描述服务,是 Swagger/OpenAPI 的基础。AddSwaggerGen()
:注册 Swagger 生成器,用于生成 OpenAPI 文档。AddDbContext<MyDbContext>()
:注册 Entity Framework Core 数据库上下文。AddIdentity<IdentityUser, IdentityRole>()
:注册 ASP.NET Core Identity 服务。AddAuthentication()
/AddJwtBearer()
:注册认证服务。AddAuthorization()
:注册授权服务(通常与认证一起使用)。AddScoped<TService, TImplementation>()
/AddTransient<...>
/AddSingleton<...>
:注册自定义服务,指定生命周期。
- 所有依赖注入容器的配置都在这里完成。
- 使用
-
var app = builder.Build();
- 在完成所有服务注册后,调用
Build()
方法。 - 这个方法根据之前的配置构建出实际的
WebApplication
实例 (app
)。 app
对象代表你的应用程序本身,用于配置中间件管道和路由。这是替代传统Startup.Configure
的地方。
- 在完成所有服务注册后,调用
-
配置中间件管道 (
app.UseXxx()
)- 中间件是处理 HTTP 请求和响应的组件,按添加到管道的顺序执行。
- 使用
app.UseXxx()
方法将中间件添加到管道中。 - 顺序至关重要! 中间件按照添加的顺序执行。例如:
- 异常处理 (
UseExceptionHandler
) 通常应放在最前面,以便捕获后续中间件的所有异常。 - HTTPS 重定向 (
UseHttpsRedirection
) 应在处理敏感数据(如认证、静态文件)之前。 - 静态文件 (
UseStaticFiles
) 通常放在认证之前,因为像图片、CSS 这些静态文件通常不需要认证。 - 路由 (
UseRouting
):在 Minimal API 中,MapXxx
方法内部通常会处理路由,显式调用UseRouting()
是可选的,但有时为了明确位置会加上。它负责将请求匹配到端点。 - 认证 (
UseAuthentication
):必须在授权 (UseAuthorization
) 之前调用,用于识别用户身份。 - 授权 (
UseAuthorization
):根据认证结果和策略决定用户是否有权访问资源。 - 端点 (
UseEndpoints
):在传统 MVC 中显式使用,在 Minimal API 中被MapXxx
方法替代。
- 异常处理 (
- 环境判断 (
if (app.Environment.IsDevelopment())
) 常用于只在开发环境启用的中间件,如 Swagger UI、详细的错误页面。
-
配置端点 (
app.MapXxx()
)- 这是定义应用程序如何响应特定 URL 和 HTTP 方法(GET, POST, PUT, DELETE 等)的地方。
- Minimal API 方式: 使用
MapGet()
,MapPost()
,MapPut()
,MapDelete()
,MapMethods()
等方法直接在Program.cs
中定义端点及其处理程序(通常是 Lambda 表达式或方法)。处理程序可以:- 直接返回结果(字符串、JSON 对象、
IResult
如Results.Ok()
,Results.NotFound()
,Results.Created()
)。 - 通过参数注入依赖的服务(由 DI 容器自动提供)。
- 访问
HttpContext
。 - 使用模型绑定从请求体、查询字符串、路由数据等获取参数。
- 直接返回结果(字符串、JSON 对象、
- 控制器方式: 如果之前调用了
AddControllers()
,则可以使用app.MapControllers()
来映射所有遵循 MVC 模式的控制器类(使用[ApiController]
,[Route]
,[HttpGet]
等属性)。这种方式更适合大型或复杂 API 的组织。
-
app.Run();
- 这是应用程序的终点。调用
Run()
方法会启动 Kestrel 服务器(或其他配置的主机),开始监听传入的 HTTP 请求。 - 应用程序会一直运行,直到被关闭(Ctrl+C 或系统信号)。
- 这是应用程序的终点。调用