skills/core/configuration/SKILL.md
Use when setting up IConfiguration, Options pattern, appsettings layering, or user secrets.
npx skillsauth add faysilalshareef/dotnet-ai-kit configurationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
ValidateOnStart() for fail-fast behaviorappsettings.json < appsettings.{Environment}.json < env vars < user secretsappsettings.json — use user secrets (dev) or Key Vault (prod)IOptions<T> for singleton config, IOptionsSnapshot<T> for scoped reloadingpublic sealed 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, 3600)]
public int CommandTimeoutSeconds { get; init; } = 30;
}
public sealed class JwtOptions
{
public const string SectionName = "Jwt";
[Required]
public required string Issuer { get; init; }
[Required]
public required string Audience { get; init; }
[Required, MinLength(32)]
public required string Key { get; init; }
[Range(1, 1440)]
public int ExpiryMinutes { get; init; } = 60;
}
// Program.cs — fail fast if configuration is invalid
builder.Services.AddOptions<DatabaseOptions>()
.BindConfiguration(DatabaseOptions.SectionName)
.ValidateDataAnnotations()
.ValidateOnStart();
builder.Services.AddOptions<JwtOptions>()
.BindConfiguration(JwtOptions.SectionName)
.ValidateDataAnnotations()
.ValidateOnStart();
public sealed class DatabaseOptionsValidator : IValidateOptions<DatabaseOptions>
{
public ValidateOptionsResult Validate(string? name, DatabaseOptions options)
{
var failures = new List<string>();
if (options.ConnectionString.Contains("password=",
StringComparison.OrdinalIgnoreCase)
&& !options.ConnectionString.Contains("Encrypt=true",
StringComparison.OrdinalIgnoreCase))
{
failures.Add(
"Connections with passwords must use Encrypt=true.");
}
return failures.Count > 0
? ValidateOptionsResult.Fail(failures)
: ValidateOptionsResult.Success;
}
}
// Register the validator
builder.Services.AddSingleton<
IValidateOptions<DatabaseOptions>, DatabaseOptionsValidator>();
// Singleton — reads once at startup, never changes
public sealed class StartupService(IOptions<DatabaseOptions> options)
{
private readonly DatabaseOptions _db = options.Value;
}
// Scoped — reloads per request when config changes (requires reloadOnChange)
public sealed class RequestService(IOptionsSnapshot<DatabaseOptions> options)
{
private readonly DatabaseOptions _db = options.Value;
}
// Singleton — reloads and notifies on change
public sealed class MonitorService(IOptionsMonitor<DatabaseOptions> options)
{
public MonitorService(IOptionsMonitor<DatabaseOptions> options)
{
options.OnChange(newOptions =>
{
// React to configuration changes
});
}
}
// appsettings.json — shared defaults
{
"Database": {
"MaxRetryCount": 3,
"CommandTimeoutSeconds": 30
},
"Logging": {
"LogLevel": {
"Default": "Information"
}
}
}
// appsettings.Development.json — dev overrides
{
"Database": {
"ConnectionString": "Server=localhost;Database={Domain}Db;Trusted_Connection=true;TrustServerCertificate=true"
}
}
# Initialize user secrets
dotnet user-secrets init
# Set secrets
dotnet user-secrets set "Database:ConnectionString" "Server=localhost;..."
dotnet user-secrets set "Jwt:Key" "your-development-secret-key-min-32-chars"
# Environment variables use __ as section separator
Database__ConnectionString="Server=prod-server;..."
Jwt__Key="production-secret-key"
// Multiple instances of the same options type
builder.Services.AddOptions<StorageOptions>("azure")
.BindConfiguration("Storage:Azure")
.ValidateDataAnnotations();
builder.Services.AddOptions<StorageOptions>("aws")
.BindConfiguration("Storage:Aws")
.ValidateDataAnnotations();
// Consuming named options
public sealed class StorageFactory(IOptionsSnapshot<StorageOptions> options)
{
public IStorageClient Create(string provider)
{
var config = options.Get(provider);
return provider switch
{
"azure" => new AzureBlobClient(config),
"aws" => new S3Client(config),
_ => throw new ArgumentException($"Unknown provider: {provider}")
};
}
}
// BAD: Reading IConfiguration directly — not strongly typed
var connStr = configuration["Database:ConnectionString"];
// BAD: Secrets in appsettings.json
{
"Jwt": { "Key": "super-secret-key-DO-NOT-COMMIT" }
}
// BAD: No validation — app fails at runtime with cryptic errors
services.Configure<DatabaseOptions>(
configuration.GetSection("Database")); // no ValidateOnStart
// BAD: Using IOptions<T> when you need config reload
public class ReloadableService(IOptions<FeatureFlags> options) { }
// Should use IOptionsSnapshot or IOptionsMonitor
IOptions<, IOptionsSnapshot<, IOptionsMonitor< in constructorsBindConfiguration or Bind calls in Program.csValidateOnStart or ValidateDataAnnotations callsappsettings.json for configuration sectionsIConfiguration reads (configuration["Key"])UserSecretsId in .csproj (user secrets enabled)IOptions<T> injectionValidateOnStart()dotnet user-secrets init then set values| Scenario | Interface | Notes |
|----------|-----------|-------|
| Singleton service needs config | IOptions<T> | Reads once |
| Scoped service needs live config | IOptionsSnapshot<T> | Reloads per scope |
| React to config changes | IOptionsMonitor<T> | Change callbacks |
| Multiple named configs | IOptionsSnapshot<T> with .Get(name) | Named options |
| Startup validation | ValidateOnStart() | Fail-fast |
data-ai
Use when about to claim work is complete, fixed, passing, or ready — before committing, creating PRs, or moving to the next task. Requires running verification commands and confirming output before making any success claims.
development
Use when encountering any bug, test failure, build error, or unexpected behavior — before proposing fixes or making changes.
development
Use when checkpointing, wrapping up, or handing off an AI-assisted development session.
development
Use when following the Specification-Driven Development lifecycle from plan through ship.