DotNetSafeConfig 1.0.0
dotnet add package DotNetSafeConfig --version 1.0.0
NuGet\Install-Package DotNetSafeConfig -Version 1.0.0
<PackageReference Include="DotNetSafeConfig" Version="1.0.0" />
<PackageVersion Include="DotNetSafeConfig" Version="1.0.0" />
<PackageReference Include="DotNetSafeConfig" />
paket add DotNetSafeConfig --version 1.0.0
#r "nuget: DotNetSafeConfig, 1.0.0"
#:package DotNetSafeConfig@1.0.0
#addin nuget:?package=DotNetSafeConfig&version=1.0.0
#tool nuget:?package=DotNetSafeConfig&version=1.0.0
DotNetSafeConfig
Configuration validation and secrets management to prevent missing config keys, validate settings, and handle secrets safely.
Problems Solved
- IOptions returning null:
IOptions<T>returns null when configuration is missing - Missing config keys in production: Configuration keys missing in production cause runtime errors
- Secrets committed: Secrets accidentally committed to source control
- No config validation: Configuration not validated until runtime
- Docker env vars not loading: Environment variables not loaded in Docker containers
- appsettings overrides confusion: Unclear which configuration takes precedence
- Azure/AppConfig mismatch: Configuration mismatch between local and Azure
- Config drift between environments: Configuration differences between dev/staging/prod
- Secrets logged: Secrets accidentally logged in application logs
- Runtime config reload issues: Configuration reload not working properly
Installation
dotnet add package DotNetSafeConfig
Quick Start
1. Validate Required Configuration Keys
Problem: Missing configuration keys cause runtime errors in production.
using DotNetSafeConfig;
// ✅ GOOD: Validate configuration on startup
builder.Services.AddConfigValidation(validator =>
{
validator.RequireKey("Database:ConnectionString");
validator.RequireKey("AppSettings:ApiKey");
validator.RequireKey("ExternalServices:PaymentGateway:Url");
});
// Validation happens automatically on startup
2. Validate IOptions with Data Annotations
Problem: IOptions<T> returns null or invalid values without validation.
// ✅ GOOD: Define configuration class with validation
public class AppSettings
{
[Required]
public string ApiKey { get; set; } = string.Empty;
[Required]
[Url]
public string ApiUrl { get; set; } = string.Empty;
[Range(1, 100)]
public int MaxRetries { get; set; } = 3;
}
// Register with validation
builder.Services.AddValidatedOptions<AppSettings>(
configuration,
"AppSettings"
);
// Use validated options
public class MyService
{
private readonly AppSettings _settings;
public MyService(AppSettings settings) // Injected as validated instance
{
_settings = settings; // Guaranteed to be valid
}
}
3. Safe Secrets Management
Problem: Secrets accidentally logged or exposed in error messages.
// ❌ BAD: Secret might be logged
logger.LogInformation("API Key: {ApiKey}", apiKey);
// ✅ GOOD: Mask secrets before logging
var apiKey = SecretsHelper.GetRequiredSecret(configuration, "ApiKey", logger);
var masked = SecretsHelper.MaskSecret(apiKey); // "abcd****"
logger.LogInformation("API Key: {ApiKey}", masked);
4. Detect Placeholder Values
Problem: Placeholder values like "your-secret-here" deployed to production.
// ✅ GOOD: Detect and warn about placeholder values
var apiKey = SecretsHelper.GetRequiredSecret(configuration, "ApiKey", logger);
if (SecretsHelper.IsPlaceholderValue(apiKey))
{
logger.LogWarning("API Key appears to be a placeholder value");
}
5. Filter Secrets from Logs
Problem: Secrets included in configuration dictionaries that get logged.
// ✅ GOOD: Filter secrets before logging
var config = new Dictionary<string, string>
{
["ApiKey"] = "secret-key-123",
["DatabasePassword"] = "db-pass-456",
["PublicSetting"] = "public-value"
};
var safeConfig = SecretsHelper.FilterSecrets(
config,
"ApiKey",
"DatabasePassword"
);
logger.LogInformation("Configuration: {Config}", safeConfig);
// Logs: ApiKey: "abcd****", DatabasePassword: "db-p****"
Real-World Example
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Validate all required configuration
builder.Services.AddConfigValidation(validator =>
{
// Environment variables
validator.RequireKey("DATABASE_CONNECTION_STRING");
// Configuration keys
validator.RequireKey("AppSettings:ApiKey");
validator.RequireKey("AppSettings:JwtSecret");
validator.RequireKey("ExternalServices:PaymentGateway:Url");
validator.RequireKey("ExternalServices:PaymentGateway:ApiKey");
});
// Register validated options
builder.Services.AddValidatedOptions<AppSettings>(
builder.Configuration,
"AppSettings"
);
builder.Services.AddValidatedOptions<DatabaseSettings>(
builder.Configuration,
"Database"
);
var app = builder.Build();
// Validate startup
try
{
var validator = app.Services.GetRequiredService<ConfigValidator>();
validator.Validate();
app.Logger.LogInformation("Configuration validation passed");
}
catch (ConfigurationValidationException ex)
{
app.Logger.LogCritical(ex, "Configuration validation failed");
Environment.Exit(1);
}
app.Run();
}
}
// Configuration classes with validation
public class AppSettings
{
[Required]
[MinLength(32)]
public string ApiKey { get; set; } = string.Empty;
[Required]
[Url]
public string ApiUrl { get; set; } = string.Empty;
[Range(1, 10)]
public int MaxRetries { get; set; } = 3;
}
public class DatabaseSettings
{
[Required]
public string ConnectionString { get; set; } = string.Empty;
[Range(5, 100)]
public int CommandTimeout { get; set; } = 30;
}
// Service using validated configuration
public class PaymentService
{
private readonly AppSettings _settings;
private readonly ILogger<PaymentService> _logger;
public PaymentService(AppSettings settings, ILogger<PaymentService> logger)
{
_settings = settings; // Guaranteed to be valid
_logger = logger;
}
public async Task ProcessPaymentAsync(PaymentRequest request)
{
// Safe to use - configuration is validated
var maskedKey = SecretsHelper.MaskSecret(_settings.ApiKey);
_logger.LogInformation("Processing payment with API: {ApiUrl}, Key: {Key}",
_settings.ApiUrl, maskedKey);
// Process payment...
}
}
Configuration Validation Example
// Validate on startup
builder.Services.AddConfigValidation(validator =>
{
// Required environment variables
validator.RequireKey("DATABASE_CONNECTION_STRING");
validator.RequireKey("REDIS_CONNECTION_STRING");
// Required configuration sections
validator.RequireKey("AppSettings:ApiKey");
validator.RequireKey("AppSettings:JwtSecret");
validator.RequireKey("ExternalServices:PaymentGateway:Url");
// Optional but recommended
validator.RequireKey("Logging:LogLevel:Default");
});
Best Practices
- Validate all required configuration on application startup
- Use Data Annotations on configuration classes for type validation
- Mask secrets before logging using
SecretsHelper.MaskSecret() - Detect placeholder values to prevent deploying test values
- Filter secrets from dictionaries before logging configuration
- Fail fast - exit immediately if required configuration is missing
- Use validated options instead of raw
IOptions<T>
API Reference
ConfigValidator- Validates required configuration keysOptionsValidator<T>- ValidatesIOptions<T>using Data AnnotationsSecretsHelper- Utilities for safe secret handlingAddConfigValidation()- Extension method to add validationAddValidatedOptions<T>()- Extension method to register validated options
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.Extensions.Configuration (>= 8.0.0)
- Microsoft.Extensions.Configuration.Binder (>= 8.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Logging (>= 8.0.0)
- Microsoft.Extensions.Options (>= 8.0.0)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 8.0.0)
- System.ComponentModel.Annotations (>= 5.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 183 | 1/5/2026 |
Initial release. See README for details.