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 之间。
- 给创建任务和完成任务增加结构化日志。