本指南提供了使用 Apq.Cfg 进行配置管理的最佳实践,帮助开发者构建更加健壮、安全和可维护的配置系统。
配置层级是 Apq.Cfg 的核心概念,数值越大优先级越高。建议遵循以下层级设计原则:
var cfg = new CfgBuilder()
// 0层:系统默认值
.AddJson("config.json", level: 0, writeable: false)
// 1层:环境特定默认值
.AddJson($"config.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json",
level: 1, writeable: false)
// 5层:环境变量
.AddEnvironmentVariables(level: 5, prefix: "APP_")
// 8层:用户特定配置(可选)
.AddJson("user.config.json", level: 8, writeable: true, isPrimaryWriter: true)
.Build();
避免将敏感信息(如密码、API密钥)直接存储在配置文件中:
// 推荐:使用外部配置中心
var cfg = new CfgBuilder()
.AddJson("config.json", level: 0, writeable: false)
.AddSource(new VaultCfgSource("secret/", level: 5, token: vaultToken)) // 从 HashiCorp Vault 加载
.Build();
// 避免:直接在配置文件中存储敏感信息
// {
// "ConnectionStrings": {
// "DefaultConnection": "Server=myServerAddress;Database=myDataBase;User Id=myUsername;password=myPassword;"
// }
// }
对需要本地存储的敏感配置进行加密:
// 使用自定义加密配置源
var cfg = new CfgBuilder()
.AddJson("config.json", level: 0, writeable: false)
.AddSource(new EncryptedJsonCfgSource("config.encrypted.json", level: 2,
writeable: false, encryptionKey: encryptionKey))
.Build();
实施最小权限原则,限制配置源的访问权限:
// 生产环境配置文件权限设置
// - config.json: 只读 (应用程序服务账户)
// - config.Production.json: 只读 (配置管理服务账户)
// - config.Development.json: 读写 (开发者账户)
为不同环境维护独立的配置文件:
/config
├── config.json # 基础配置
├── config.Development.json # 开发环境覆盖
├── config.Staging.json # 预发布环境覆盖
└── config.Production.json # 生产环境覆盖
建立清晰的环境变量命名约定:
// 推荐:使用层次化命名
var cfg = new CfgBuilder()
.AddEnvironmentVariables(level: 5, prefix: "APP_")
// APP_ConnectionStrings__DefaultConnection
// APP_Logging__LogLevel__Default
// APP_Caching__Redis__ConnectionString
.Build();
// 避免:扁平化命名
// APP_CONNECTIONSTRING
// APP_LOGLEVEL
// APP_REDIS_CONNECTION
在应用程序启动时验证关键配置:
public class AppSettings
{
public string ConnectionString { get; set; }
public int RetryCount { get; set; }
public TimeSpan Timeout { get; set; }
[ValidateComplexType]
public class ValidateComplexType : ValidationAttribute
{
public override bool IsValid(object? value)
{
if (value is AppSettings settings)
{
// 验证连接字符串格式
if (string.IsNullOrWhiteSpace(settings.ConnectionString))
return false;
// 验证重试次数范围
if (settings.RetryCount < 0 || settings.RetryCount > 10)
return false;
// 验证超时时间范围
if (settings.Timeout < TimeSpan.FromSeconds(1) || settings.Timeout > TimeSpan.FromMinutes(5))
return false;
return true;
}
return false;
}
}
}
// 使用
var cfg = new CfgBuilder()
.AddJson("config.json", level: 0, writeable: false)
.Build();
var settings = ObjectBinder.Bind<AppSettings>(cfg.GetSection("App"));
Validator.ValidateObject(settings, new ValidationContext(settings), validateAllProperties: true);
实施配置健康检查机制:
// 定期检查关键配置的有效性
public class ConfigurationHealthCheck : IHealthCheck
{
private readonly ICfgRoot _cfg;
public ConfigurationHealthCheck(ICfgRoot cfg)
{
_cfg = cfg;
}
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default)
{
try
{
// 验证数据库连接
var connectionString = _cfg.Get<string>("ConnectionStrings:DefaultConnection");
using var connection = new SqlConnection(connectionString);
await connection.OpenAsync(cancellationToken);
return HealthCheckResult.Healthy();
}
catch (Exception ex)
{
return HealthCheckResult.Unhealthy("数据库连接失败", ex);
}
}
}
对配置文件实施版本控制:
{
"Version": "1.2.0",
"Info": {
"Description": "应用程序主配置文件",
"LastModified": "2023-12-01T10:30:00Z",
"ModifiedBy": "[email protected]"
},
"ConnectionStrings": {
"DefaultConnection": "..."
}
}
记录配置变更历史:
public class ConfigurationAuditService
{
private readonly ICfgRoot _cfg;
private readonly IAuditLogger _auditLogger;
public ConfigurationAuditService(ICfgRoot cfg, IAuditLogger auditLogger)
{
_cfg = cfg;
_auditLogger = auditLogger;
// 订阅配置变更事件
_cfg.ConfigChanges.Subscribe(OnConfigurationChanged);
}
private void OnConfigurationChanged(ConfigChangeEvent change)
{
_auditLogger.LogInformation("配置已更改: {Key}={Key}, OldValue={OldValue}, NewValue={NewValue}, ChangedAt={ChangedAt}",
change.Key,
change.OldValue,
change.NewValue,
DateTime.UtcNow);
}
}
缓存频繁访问的配置值:
public class CachedConfigurationService
{
private readonly ICfgRoot _cfg;
private readonly IMemoryCache _cache;
private readonly TimeSpan _cacheDuration = TimeSpan.FromMinutes(5);
public CachedConfigurationService(ICfgRoot cfg, IMemoryCache cache)
{
_cfg = cfg;
_cache = cache;
}
public T Get<T>(string key)
{
var cacheKey = $"cfg_{key}";
return _cache.GetOrCreate(cacheKey, () => _cfg.Get<T>(key), _cacheDuration);
}
}
使用批量操作减少配置源访问:
// 推荐:使用批量获取
var keys = new[] { "FeatureA:Enabled", "FeatureB:Enabled", "FeatureC:Enabled" };
var features = cfg.GetMany(keys);
// 避免:多次单独获取
var featureA = cfg.Get<bool>("FeatureA:Enabled");
var featureB = cfg.Get<bool>("FeatureB:Enabled");
var featureC = cfg.Get<bool>("FeatureC:Enabled");
监控配置访问模式:
public class ConfigurationMetrics
{
private readonly IMetrics _metrics;
private readonly ConcurrentDictionary<string, int> _accessCounts = new();
public void RecordAccess(string key)
{
_accessCounts.AddOrUpdate(key, 1, (_, count) => count + 1);
_metrics.Counter("configuration.access.count").Inc();
_metrics.Histogram("configuration.access.frequency").Observe(_accessCounts.Count);
}
public void ReportTopAccessedKeys()
{
var topKeys = _accessCounts.OrderByDescending(kvp => kvp.Value)
.Take(10)
.Select(kvp => kvp.Key);
_metrics.Gauge("configuration.top_keys", topKeys);
}
}
诊断配置加载问题:
public class ConfigurationDiagnostics
{
public static void LogConfigurationSources(ICfgRoot cfg)
{
var sb = new StringBuilder();
sb.AppendLine("配置源加载情况:");
// 这里需要访问内部实现,实际项目中可能需要添加诊断API
foreach (var source in cfg.GetSources())
{
sb.AppendLine($"- {source.GetType().Name}: Level={source.Level}, Writeable={source.IsWriteable}");
}
// 记录到日志或诊断系统
Console.WriteLine(sb.ToString());
}
}
配置未生效
配置值类型转换错误
配置热重载不工作
启用详细日志
var cfg = new CfgBuilder()
.AddJson("config.json", level: 0, writeable: false)
.AddEnvironmentVariables(level: 5, prefix: "APP_")
.WithEncodingDetectionLogging(result => Console.WriteLine($"编码检测: {result}"))
.Build();
导出配置快照
// 导出当前配置快照用于调试
var snapshot = cfg.ExportSnapshot();
File.WriteAllText("debug-config.json", snapshot);
配置诊断工具
// 创建诊断工具
var diagnostics = new ConfigurationDiagnostics(cfg);
diagnostics.ValidateRequiredKeys();
diagnostics.ReportConflictingValues();
diagnostics.CheckForDeprecatedSettings();