ASP.NET Core 应用程序的启动与配置:Program.cs 文件的全面解析
Program.cs
是 ASP.NET Core 应用程序的入口点,负责应用程序的启动和配置。以下是 Program.cs
文件中完成的主要工作,按逻辑步骤进行总结:
1. 创建和配置主机环境
- 创建 WebApplication 构建器 :
- 使用
WebApplication.CreateBuilder(args)
创建一个WebApplicationBuilder
实例,该实例用于配置应用程序的主机和服务。 - 自动加载配置文件(如
appsettings.json
)和命令行参数,并设置日志记录、依赖注入等基础功能。
- 使用
2. 获取配置和环境对象
- 获取配置和环境信息 :
- 通过
builder.Configuration
获取应用程序的配置对象,可以从多个来源(如appsettings.json
、环境变量等)读取配置。 - 通过
builder.Environment
获取当前的运行环境(如开发、生产等),以便根据不同的环境配置中间件和行为。 - 创建并配置日志记录器,确保可以在
Program.cs
中记录日志,使用控制台输出日志。
- 通过
3. 加载和验证应用程序设置
- 加载
AppSettings
:- 从配置中加载
AppSettings
配置节,并将其绑定到AppSettings
类型的对象。 - 将
AppSettings
注册到依赖注入容器中,以便后续可以注入到其他服务中。 - 记录一条调试日志,表明
AppSettings
已成功加载。
- 从配置中加载
4. 配置 Application Insights
- 启用 Application Insights :
- 如果
AppSettings
中启用了 Application Insights,则调用AddApplicationInsightsTelemetry()
来配置和启用 Application Insights 监控。 - 记录一条跟踪日志,表明 Application Insights 已配置。
- 如果
5. 配置 API 版本控制
- 添加 API 版本控制 :
- 使用
AddApiVersioning()
配置 API 版本控制,确保 API 请求能够根据 URL 或请求头中的版本信息路由到正确的控制器和操作。 - 启用 API 版本报告,并设置默认版本为
1.0
。 - 使用
AddVersionedApiExplorer()
启用 API 版本探索功能,自动注册IApiVersionDescriptionProvider
,以便在 Swagger 中显示不同版本的 API 文档。
- 使用
6. 配置 Swagger 和 API 文档
- 启用 Swagger :
- 如果
AppSettings
中启用了 Swagger,则配置 Swagger 和 Swagger UI。 - 注册
ConfigureSwaggerOptions
以自定义 Swagger 的生成选项。 - 通过
AddSwaggerGen()
配置 Swagger 文档生成,包括从 XML 注释文件中提取注释。 - 确保每个 API 版本都有对应的 Swagger 文档端点,并在 Swagger UI 中显示。
- 如果
7. 配置依赖注入
- 注册业务服务和映射 :
- 调用
ConfigureMappings()
和ConfigureBusinessServices()
方法,注册应用程序所需的业务服务和映射配置。 - 这些方法通常会配置数据访问层、业务逻辑层等服务,并将它们注册到依赖注入容器中。
- 调用
8. 构建应用程序
- 构建
WebApplication
实例 :- 调用
builder.Build()
构建WebApplication
实例,完成所有配置和服务的初始化。 app
是WebApplication
的实例,用于配置 HTTP 请求管道并启动应用程序。
- 调用
9. 配置 HTTP 请求管道
- 配置中间件 :
- 根据当前环境配置不同的中间件:
- 开发环境:启用开发者异常页面,方便调试。
- 生产环境:启用自定义异常处理中间件,捕获未处理的异常并返回适当的错误响应;启用 HTTPS 重定向和 HSTS(HTTP 严格传输安全)。
- 配置常见的中间件,如
UseHttpsRedirection()
、UseRouting()
、UseAuthorization()
和UseRequestLocalization()
,确保请求正确路由和授权。 - 使用
UseEndpoints()
配置终结点映射,将请求路由到控制器。
- 根据当前环境配置不同的中间件:
10. 配置 Swagger UI
- 启用 Swagger UI :
- 如果
AppSettings
中启用了 Swagger,并且 API 版本控制已配置,则启用 Swagger UI。 - 通过
IApiVersionDescriptionProvider
获取所有 API 版本的描述,并为每个版本配置相应的 Swagger 文档端点。 - 确保每个版本的 API 文档都能在 Swagger UI 中正确显示。
- 如果
11. 启动应用程序
- 启动 WebApplication :
- 最后,调用
app.Run()
启动应用程序,使其开始监听传入的 HTTP 请求并处理它们。
- 最后,调用
总结
Program.cs
文件的主要职责是:
- 配置应用程序的主机和服务,包括加载配置、设置日志记录、启用监控(如 Application Insights)、配置 API 版本控制和 Swagger 文档。
- 构建 HTTP 请求管道,配置中间件以处理请求、路由、授权和异常处理。
- 启动应用程序,使其开始监听和处理 HTTP 请求。
通过这些步骤,Program.cs
确保了应用程序的正确初始化和运行,提供了良好的开发和生产环境支持。
Program.cs解释如下
csharp
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
// 创建 WebApplication 构建器,它会读取命令行参数并初始化主机环境。
var builder = WebApplication.CreateBuilder(args);
// 获取应用程序的配置对象(Configuration)和环境对象(Environment)
// 这些是 ASP.NET Core 应用程序的基础组件,用于访问配置文件和环境信息。
var configuration = builder.Configuration;
var env = builder.Environment;
// 使用构建的服务提供者提前创建日志记录器实例。
// 这样可以在 Program.cs 中使用日志记录功能,而不需要依赖 Startup 类。
var serviceProvider = builder.Services.BuildServiceProvider();
var logger = serviceProvider.GetRequiredService<ILogger<Program>>();
// 从配置中获取 AppSettings 配置节。
// AppSettings 是应用程序的主要配置部分,通常包含应用程序的运行时设置。
var appsettingsConfigurationSection = configuration.GetSection(nameof(AppSettings));
// 如果没有找到 AppSettings 配置节,则抛出异常,确保应用程序不会在缺少关键配置的情况下启动。
if (appsettingsConfigurationSection == null)
throw new Exception("No appsettings has been found");
// 将 AppSettings 配置节绑定到 AppSettings 类型的对象,并注册到依赖注入容器中。
// 这使得 AppSettings 可以通过依赖注入在应用程序的其他部分使用。
var appSettings = appsettingsConfigurationSection.Get<AppSettings>();
builder.Services.Configure<AppSettings>(appsettingsConfigurationSection);
logger.LogDebug("AppSettings loaded for DI"); // 记录日志,表明 AppSettings 已加载到依赖注入容器中。
// 从配置中获取 ApplicationInsights 配置节,并检查是否启用了 Application Insights。
// Application Insights 是一个应用性能管理服务,用于监控应用程序的性能和使用情况。
var applicationInsightsConfiturationSection = configuration.GetSection(nameof(ApplicationInsights));
if (applicationInsightsConfiturationSection != null && applicationInsightsConfiturationSection.Get<ApplicationInsights>().Enabled)
{
// 如果启用了 Application Insights,则添加 Application Insights 的遥测服务。
// 这将使应用程序能够发送遥测数据到 Azure Monitor。
builder.Services.AddApplicationInsightsTelemetry();
logger.LogTrace("Configuring Application Insights"); // 记录日志,表明正在配置 Application Insights。
}
try
{
if (appSettings.IsValid())
{
logger.LogDebug("Valid AppSettings"); // 记录日志,表明 AppSettings 有效。
// 添加 MVC 控制器支持,并设置默认返回的内容类型为 JSON。
// ProducesAttribute 确保所有控制器操作默认返回 JSON 格式的数据。
builder.Services.AddControllers(opt =>
{
opt.Filters.Add(new ProducesAttribute("application/json"));
}).SetCompatibilityVersion(CompatibilityVersion.Latest);
// 添加 API 版本控制支持,设置默认版本为 1.0,并启用 URL 段读取版本号。
// 这允许应用程序根据 URL 中的版本号来区分不同的 API 版本。
builder.Services.AddApiVersioning(o =>
{
o.ReportApiVersions = true;
o.AssumeDefaultVersionWhenUnspecified = true;
o.DefaultApiVersion = new ApiVersion(1, 0);
o.ApiVersionReader = new UrlSegmentApiVersionReader();
});
// 添加 API 版本探索支持,以便 Swagger 可以显示不同版本的 API。
// GroupNameFormat 设置了 API 版本的命名格式,SubstituteApiVersionInUrl 确保版本号出现在 URL 中。
builder.Services.AddVersionedApiExplorer(options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
// 如果启用了 Swagger,则配置 Swagger 和 Swagger UI。
// Swagger 是一个工具,用于生成和展示 API 文档。
if (appSettings.Swagger.Enabled)
{
// 注册 Swagger 选项配置类,用于自定义 Swagger 的行为。
builder.Services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
// 配置 Swagger 生成器,包括操作过滤器和 XML 文档注释。
// XML 文档注释提供了 API 方法的详细说明,帮助开发者更好地理解 API。
builder.Services.AddSwaggerGen(options =>
{
options.OperationFilter<SwaggerDefaultValues>();
// 获取当前程序集及其引用的所有程序集。
var allAssemblies = new[] { Assembly.GetExecutingAssembly() }
.Union(Assembly.GetExecutingAssembly().GetReferencedAssemblies()
.Select(a => Assembly.Load(a)));
// 遍历所有程序集,查找并包含对应的 XML 文档注释文件。
foreach (var assembly in allAssemblies)
{
var xmlFile = $"{assembly.GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
if (File.Exists(xmlPath))
{
options.IncludeXmlComments(xmlPath);
}
}
});
}
// 注册映射和业务服务配置。
// 这些配置可能包括 AutoMapper 映射、数据库上下文、服务注册等。
builder.Services.ConfigureMappings();
builder.Services.ConfigureBusinessServices(configuration);
logger.LogDebug("ApiVersioning, Swagger and DI settings configured"); // 记录日志,表明 API 版本控制、Swagger 和依赖注入已配置完成。
}
else
{
logger.LogDebug("Invalid AppSettings"); // 记录日志,表明 AppSettings 无效。
}
}
catch (Exception ex)
{
// 捕获配置过程中可能出现的任何异常,并记录错误信息。
// 这有助于在应用程序启动失败时进行调试。
logger.LogError(ex.Message);
}
// 构建 WebApplication 实例,准备启动应用程序。
var app = builder.Build();
// 配置 HTTP 请求管道,根据环境选择不同的中间件。
logger.LogTrace("Configuring HTTP request pipeline"); // 记录日志,表明开始配置 HTTP 请求管道。
logger.LogDebug($"Environment: {env.EnvironmentName}"); // 记录当前环境名称。
try
{
if (env.IsDevelopment())
{
// 在开发环境中,使用开发者异常页面,提供更详细的错误信息。
// 开发者异常页面会显示完整的堆栈跟踪,帮助开发者快速定位问题。
app.UseDeveloperExceptionPage();
logger.LogInformation("Developer exception page loaded."); // 记录日志,表明开发者异常页面已加载。
}
else
{
// 在生产环境中,使用自定义的异常处理中间件,并启用 HSTS(HTTP 严格传输安全)。
// 自定义异常处理中间件捕获未处理的异常,并返回友好的错误响应。
app.UseExceptionHandler(a => a.Run(async context =>
{
var feature = context.Features.Get<IExceptionHandlerPathFeature>();
var exception = feature.Error;
var code = HttpStatusCode.InternalServerError;
// 根据异常类型设置适当的 HTTP 状态码。
if (exception is ArgumentNullException) code = HttpStatusCode.BadRequest;
else if (exception is ArgumentException) code = HttpStatusCode.BadRequest;
else if (exception is UnauthorizedAccessException) code = HttpStatusCode.Unauthorized;
// 记录全局错误处理器捕获的异常信息。
logger.LogError($"GLOBAL ERROR HANDLER::HTTP:{code}::{exception.Message}");
// 使用 Newtonsoft.Json 序列化异常信息,并将其作为 JSON 响应返回给客户端。
var result = Newtonsoft.Json.JsonConvert.SerializeObject(exception, Newtonsoft.Json.Formatting.Indented);
context.Response.Clear();
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(result);
}));
// 启用 HSTS,强制浏览器只通过 HTTPS 访问应用程序。
app.UseHsts();
}
// 使用 HTTPS 重定向中间件,强制所有请求通过 HTTPS。
// 这确保了即使用户通过 HTTP 访问,也会被自动重定向到 HTTPS。
app.UseHttpsRedirection();
// 使用路由中间件,解析 URL 并分发到相应的控制器或处理器。
// 路由中间件负责将传入的 HTTP 请求映射到正确的控制器和操作。
app.UseRouting();
// 使用授权中间件,执行身份验证和授权逻辑。
// 授权中间件确保只有经过身份验证和授权的用户才能访问受保护的资源。
app.UseAuthorization();
// 使用请求本地化中间件,设置应用程序的区域性。
// 请求本地化中间件可以根据用户的语言和文化设置来调整应用程序的行为。
app.UseRequestLocalization();
// 使用终结点中间件,映射控制器路由。
// 终结点中间件负责实际处理 HTTP 请求并将响应返回给客户端。
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
// 如果启用了 Swagger,则配置 Swagger UI。
// Swagger UI 提供了一个交互式的界面,开发者可以通过它浏览和测试 API。
if (appSettings.IsValid() && appSettings.Swagger.Enabled)
{
// 使用 Swagger 中间件,提供 API 文档。
app.UseSwagger();
// 使用 Swagger UI 中间件,提供交互式的 API 文档界面。
app.UseSwaggerUI(options =>
{
// 获取 API 版本描述提供者,用于生成不同版本的 Swagger 文档。
var provider = app.ServiceProvider.GetRequiredService<IApiVersionDescriptionProvider>();
// 为每个 API 版本添加 Swagger 端点。
foreach (var description in provider.ApiVersionDescriptions)
{
options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
}
});
}
}
catch (Exception ex)
{
// 捕获配置 HTTP 请求管道过程中可能出现的任何异常,并记录错误信息。
// 这有助于在应用程序启动失败时进行调试。
logger.LogError(ex.Message);
}
// 启动应用程序,开始监听传入的 HTTP 请求。
// 一旦应用程序启动,它将开始处理来自客户端的 HTTP 请求。
app.Run();
逐行解释
-
引入命名空间 :这些命名空间包含了 ASP.NET Core 所需的各种类和接口,例如
WebApplication
、IConfiguration
、ILogger
等。 -
创建 WebApplication 构建器 :
WebApplication.CreateBuilder(args)
是 .NET 6+ 推荐的方式,用于创建和配置应用程序的主机环境。它会自动加载配置文件(如appsettings.json
)、设置日志记录等。 -
获取配置和环境对象 :
configuration
和env
是 ASP.NET Core 应用程序的基础组件,分别用于访问配置文件和环境信息。configuration
用于读取应用程序的配置,env
用于确定当前的运行环境(如开发、生产等)。 -
创建日志记录器实例 :我们使用
builder.Services.BuildServiceProvider()
提前创建IServiceProvider
,从而可以在Program.cs
中获取ILogger<Program>
实例。这与你在Startup
构造函数中获取ILogger<Startup>
的方式一致。 -
加载 AppSettings 配置节 :从配置文件中获取
AppSettings
配置节,并检查其是否存在。如果不存在,则抛出异常,确保应用程序不会在缺少关键配置的情况下启动。 -
注册 AppSettings 到依赖注入容器 :将
AppSettings
配置节绑定到AppSettings
类型的对象,并注册到依赖注入容器中。这样可以在应用程序的其他部分通过依赖注入使用AppSettings
。 -
配置 Application Insights :从配置文件中获取
ApplicationInsights
配置节,并检查是否启用了 Application Insights。如果启用了,则添加 Application Insights 的遥测服务,使应用程序能够发送遥测数据到 Azure Monitor。 -
检查 AppSettings 是否有效 :如果
AppSettings
有效,则继续配置其他服务;否则,记录日志并跳过后续配置。 -
添加 MVC 控制器支持 :配置 MVC 控制器,设置默认返回的内容类型为 JSON。
ProducesAttribute
确保所有控制器操作默认返回 JSON 格式的数据。 -
添加 API 版本控制支持:配置 API 版本控制,设置默认版本为 1.0,并启用 URL 段读取版本号。这允许应用程序根据 URL 中的版本号来区分不同的 API 版本。
-
添加 API 版本探索支持 :配置 API 版本探索,以便 Swagger 可以显示不同版本的 API。
GroupNameFormat
设置了 API 版本的命名格式,SubstituteApiVersionInUrl
确保版本号出现在 URL 中。 -
配置 Swagger:如果启用了 Swagger