关于 configuration
面向 .NET 开发的配置实践指南,介绍如何使用强类型选项、验证和分层配置源管理应用设置。也涵盖机密信息处理和命名选项配置。
主要功能
- 01强类型选项绑定
- 02启动时验证配置
- 03分层配置来源
- 04机密信息存储建议
- 05命名选项
适用场景
- 01将设置绑定到经过验证的类
- 02在启动时发现配置错误
- 03将机密信息与源代码分离
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ codewithmukesh/ dotnet-claude-kit --skill configuration安装后在 Claude Code 中输入/configuration确认已加载。
详细介绍
配置
核心原则
- 始终使用 Options 模式 — 切勿在服务中直接读取
IConfiguration。将配置节绑定到强类型类,并进行验证。 - 启动时验证 — 使用
ValidateDataAnnotations()和ValidateOnStart(),在首次请求前发现配置错误。 - 源代码中绝不包含密钥 — 开发时使用用户机密,生产环境使用 Azure Key Vault 或环境变量。切勿将密钥提交到 git。
- 配置分层 —
appsettings.json→appsettings.{Environment}.json→ 环境变量 → 用户机密。后面的来源会覆盖前面的来源。
模式
Options 模式
// Options class with validation attributes
public class DatabaseOptions
{
public const string SectionName = "Database";
[Required]
public required string ConnectionString { get; init; }
[Range(1, 100)]
public int MaxRetryCount { get; init; } = 3;
[Range(1, 60)]
public int CommandTimeoutSeconds { get; init; } = 30;
}
// Registration with validation
builder.Services.AddOptions<DatabaseOptions>()
.BindConfiguration(DatabaseOptions.SectionName)
.ValidateDataAnnotations()
.ValidateOnStart(); // Fails at startup if configuration is invalid
// appsettings.json
{
"Database": {
"ConnectionString": "",
"MaxRetryCount": 3,
"CommandTimeoutSeconds": 30
}
}
注入 Options
// IOptions<T> — singleton, read once at startup, doesn't change
public class OrderService(IOptions<DatabaseOptions> options)
{
private readonly DatabaseOptions _db = options.Value;
}
// IOptionsSnapshot<T> — scoped, re-reads per request (for reloadable config)
public class OrderService(IOptionsSnapshot<DatabaseOptions> options)
{
private readonly DatabaseOptions _db = options.Value;
}
// IOptionsMonitor<T> — singleton, actively watches for changes
public class BackgroundWorker(IOptionsMonitor<WorkerOptions> options)
{
public void DoWork()
{
var current = options.CurrentValue; // Always latest
}
}
自定义验证(复杂规则)
builder.Services.AddOptions<JwtOptions>()
.BindConfiguration("Jwt")
.Validate(options =>
{
if (string.IsNullOrEmpty(options.Key) || options.Key.Length < 32)
return false;
if (options.ExpirationMinutes <= 0)
return false;
return true;
}, "JWT key must be at least 32 characters and expiration must be positive")
.ValidateOnStart();
Azure Key Vault(生产环境)
// Program.cs — add Key Vault as a configuration source
if (builder.Environment.IsProduction())
{
var keyVaultUri = new Uri(builder.Configuration["KeyVault:Uri"]!);
builder.Configuration.AddAzureKeyVault(keyVaultUri, new DefaultAzureCredential());
}
多环境配置
// Named options — different config per named instance
builder.Services.AddOptions<SmtpOptions>("internal")
.BindConfiguration("Smtp:Internal");
builder.Services.AddOptions<SmtpOptions>("customer")
.BindConfiguration("Smtp:Customer");
// Usage
public class EmailService(IOptionsSnapshot<SmtpOptions> options)
{
public async Task SendInternalEmail(string to, string body)
{
var smtp = options.Get("internal");
// ...
}
}
反模式
不要直接读取 IConfiguration
// BAD — stringly-typed, no validation, hard to test
public class OrderService(IConfiguration config)
{
public void Process()
{
var timeout = int.Parse(config["Database:CommandTimeout"]!);
}
}
// GOOD — strongly-typed options
public class OrderService(IOptions<DatabaseOptions> options)
{
public void Process()
{
var timeout = options.Value.CommandTimeoutSeconds;
}
}
不要将密钥放在 appsettings.json 中
// BAD — committed to source control
{
"Jwt": { "Key": "super-secret-key" },
"Database": { "ConnectionString": "Server=prod;Password=secret" }
}
// GOOD — appsettings.json has defaults/structure only
{
"Jwt": { "Key": "", "Issuer": "myapp", "Audience": "myapp" },
"Database": { "ConnectionString": "" }
}
// Secrets provided via user-secrets (dev) or env vars / Key Vault (prod)
不要跳过启动验证
// BAD — misconfiguration discovered at runtime
builder.Services.Configure<JwtOptions>(builder.Configuration.GetSection("Jwt"));
// GOOD — fail fast at startup
builder.Services.AddOptions<JwtOptions>()
.BindConfiguration("Jwt")
.ValidateDataAnnotations()
.ValidateOnStart();
决策指南
| 场景 | 建议 |
|---|---|
| 将配置绑定到类 | 使用 BindConfiguration 的 Options 模式 |
| 简单、不可变的配置 | IOptions<T> |
| 每个请求都会变化的配置 | IOptionsSnapshot<T> |
| 监视配置的后台服务 | IOptionsMonitor<T> |
| 开发环境密钥 | dotnet user-secrets |
| 生产环境密钥 | Azure Key Vault 或环境变量 |
| 验证配置 | ValidateDataAnnotations() + ValidateOnStart() |
| 同一类型的多个配置 | 使用 IOptionsSnapshot<T>.Get(name) 的命名 Options |
评论
支持 Markdown