跳到主要内容

4.5 配置、Options 与日志

配置决定应用在不同环境中的行为,日志负责记录运行过程。二者一起支撑本地开发、测试、部署和生产排障。

学习目标

  • 能读取 appsettings.json、环境变量和命令行配置。
  • 能用 Options 模式绑定强类型配置。
  • 能写结构化日志,而不是拼接字符串。
  • 能区分开发、测试和生产环境配置。

应用场景

  • 管理数据库连接字符串、JWT 配置和第三方服务地址。
  • 为不同环境使用不同日志级别。
  • 排查某个请求失败时的输入、状态和异常。
  • 在 CI/CD 中通过环境变量注入敏感配置。

Options 示例

{
"TodoRules": {
"MaxTitleLength": 120,
"AllowEmptyDescription": true
}
}
public sealed class TodoRulesOptions
{
public int MaxTitleLength { get; init; } = 120;
public bool AllowEmptyDescription { get; init; } = true;
}

builder.Services
.AddOptions<TodoRulesOptions>()
.Bind(builder.Configuration.GetSection("TodoRules"))
.Validate(options => options.MaxTitleLength > 0, "标题长度必须大于 0")
.ValidateOnStart();

结构化日志示例

public sealed class TodoService(
AppDbContext dbContext,
ILogger<TodoService> logger)
{
public async Task CompleteAsync(int id, CancellationToken cancellationToken)
{
var todo = await dbContext.Todos.FindAsync([id], cancellationToken);
if (todo is null)
{
logger.LogWarning("Todo {TodoId} was not found when completing", id);
return;
}

todo.IsCompleted = true;
await dbContext.SaveChangesAsync(cancellationToken);
logger.LogInformation("Todo {TodoId} was completed", id);
}
}

重点难点

  • 不要把密钥写进 appsettings.json 并提交仓库。
  • 日志模板使用占位符,便于后续检索和聚合。
  • 配置要启动时校验,避免运行到关键路径才发现缺配置。
  • 生产环境日志既要足够排障,又不能记录密码、Token 等敏感数据。

常见误区

误区推荐做法
用字符串拼接日志使用结构化日志模板和属性
到处直接读 IConfiguration用 Options 模式集中绑定和校验
开发和生产共用配置用环境配置和环境变量隔离

练习

  • 为 Todo 标题最大长度增加 Options 配置。
  • 写启动校验:最大长度必须在 1 到 200 之间。
  • 给创建任务和完成任务增加结构化日志。