10.1 Web 应用架构与 HTTP 协议
核心概念:ASP.NET Core 采用 “请求 - 响应” 模型,基于 HTTP/HTTPS 协议通信。HTTP 协议核心要素包括:请求方法(GET/POST/PUT/DELETE)、状态码(200 成功 / 404 未找到 / 500 服务器错误)、请求头(Authorization/Content-Type)、响应头(Cache-Control)。
架构分层:表现层(API 控制器 / 页面)→业务逻辑层(服务)→数据访问层(EF Core),通过依赖注入解耦各层。
10.2ASP.NETCore 项目结构解析
典型项目结构(.NET 8 Web API):
MyWebApi/├─ Controllers/ # 控制器(处理HTTP请求)├─ Services/ # 业务逻辑服务├─ Models/ # 数据模型(请求/响应/实体)├─ Data/ # 数据访问(DbContext)├─ appsettings.json # 配置文件(连接字符串/日志)├─ Program.cs # 入口文件(服务注册/中间件管道)└─ MyWebApi.csproj # 项目依赖配置Program.cs 核心作用:注册服务(如 EF Core、认证)、构建中间件管道(处理请求流程)。
10.3 中间件管道与请求处理
中间件原理:请求依次经过多个中间件(如日志→认证→路由→控制器),每个中间件可修改请求 / 响应,或终止管道(如 401 未授权)。
自定义中间件案例:请求日志中间件(记录所有请求的路径、方法、耗时):
// 1. 定义中间件类public class RequestLoggerMiddleware{ private readonly RequestDelegate _next; private readonly ILogger<RequestLoggerMiddleware> _logger; // 构造函数注入下一个中间件和日志器 public RequestLoggerMiddleware(RequestDelegate next, ILogger<RequestLoggerMiddleware> logger) { _next = next; _logger = logger; } // 中间件核心方法(InvokeAsync) public async Task InvokeAsync(HttpContext context) { // 1. 处理请求前:记录开始时间和请求信息 var startTime = DateTime.Now; var requestPath = context.Request.Path; var httpMethod = context.Request.Method; _logger.LogInformation($"请求开始:{httpMethod} {requestPath}"); // 2. 调用下一个中间件(继续管道) await _next(context); // 3. 处理响应后:记录耗时和响应状态码 var duration = DateTime.Now - startTime; var statusCode = context.Response.StatusCode; _logger.LogInformation($"请求结束:{statusCode},耗时:{duration.TotalMilliseconds}ms"); }}// 2. 扩展方法:简化中间件注册public static class RequestLoggerMiddlewareExtensions{ public static IApplicationBuilder UseRequestLogger(this IApplicationBuilder app) { return app.UseMiddleware<RequestLoggerMiddleware>(); }}// 3. 在Program.cs注册中间件(需在路由之前)var app = builder.Build();app.UseHttpsRedirection();app.UseRequestLogger(); // 注册自定义日志中间件app.UseRouting();app.UseAuthorization();app.MapControllers();app.Run();10.4 依赖注入与服务生命周期
依赖注入(DI)核心:ASP.NET Core 内置 DI 容器,管理服务的创建与销毁,避免硬编码依赖,便于测试和维护。
服务生命周期(3 种核心类型):
生命周期 | 特点 | 适用场景 |
Transient | 每次请求创建新实例 | 轻量级、无状态服务(如工具类) |
Scoped | 每个 HTTP 请求内复用一个实例 | 数据访问服务(如 DbContext) |
Singleton | 应用启动后创建一个实例,全局复用 | 全局配置、缓存服务 |
实战案例:注册与使用业务服务:
// 1. 定义业务接口与实现public interface IUserService{ Task<string> GetUserNameByIdAsync(int id);}public class UserService : IUserService{ private readonly AppDbContext _dbContext; // 注入DbContext(Scoped生命周期) public UserService(AppDbContext dbContext) { _dbContext = dbContext; } public async Task<string> GetUserNameByIdAsync(int id) { var user = await _dbContext.Users.FindAsync(id); return user?.Name ?? "未知用户"; }}// 2. 在Program.cs注册服务(Scoped生命周期)builder.Services.AddScoped<IUserService, UserService>();// 注册DbContext(默认Scoped)builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));// 3. 在控制器中注入使用[ApiController][Route("api/[controller]")]public class UserController : Controllerbase{ private readonly IUserService _userService; // 构造函数注入IUserService public UserController(IUserService userService) { _userService = userService; } [HttpGet("{id}")] public async Task<IActionResult> GetUserName(int id) { var name = await _userService.GetUserNameByIdAsync(id); return Ok(new { UserId = id, UserName = name }); }}10.5 配置系统与环境管理
配置来源优先级(从高到低):命令行参数 → 环境变量 → appsettings.{Environment}.json → appsettings.json → 内置配置。
实战案例:多环境配置与读取:
创建环境配置文件:
- appsettings.Development.json(开发环境):
{ "Logging": { "LogLevel": { "Default": "Debug" } }, "AppSettings": { "ApibaseUrl": "https://dev.api.com", "MaxRetryCount": 2 }}- appsettings.Production.json(生产环境):
{ "Logging": { "LogLevel": { "Default": "Warning" } }, "AppSettings": { "ApibaseUrl": "https://prod.api.com", "MaxRetryCount": 5 }}- 绑定配置到实体类:
// 定义配置实体public class AppSettings{ public string ApibaseUrl { get; set; } public int MaxRetryCount { get; set; }}// 在Program.cs绑定配置builder.Services.Configure<AppSettings>( builder.Configuration.GetSection("AppSettings"));- 使用配置(控制器或服务中):
public class ConfigController : Controllerbase{ private readonly IOptions<AppSettings> _appSettings; // 注入IOptions<AppSettings> public ConfigController(IOptions<AppSettings> appSettings) { _appSettings = appSettings; } [HttpGet("settings")] public IActionResult GetSettings() { var settings = _appSettings.Value; return Ok(new { CurrentEnv = builder.Environment.EnvironmentName, // 获取当前环境(Development/Production) ApiUrl = settings.ApibaseUrl, MaxRetry = settings.MaxRetryCount }); }}- 切换环境:运行时通过命令行指定环境:dotnet run --environment Production。
