Receber por email
← Voltar para o catálogo

dotnet-options-pattern

Implements the Options pattern for strongly-typed configuration in .NET. Covers IOptions<T>, IOptionsSnapshot<T>, and IOptionsMonitor<T> with validation and reload support.

66estrelas
Atualizado há 5 meses

Ver no GitHub ↗

Como adicionar

/plugin marketplace add ronnythedev/dotnet-clean-architecture-skills

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/dotnet-options-pattern/svg)](https://www.skillteca.com.br/skills/dotnet-options-pattern)

Skills relacionadas

Ver todas de Desenvolvimento →

Alerta por categoria

Receba novas skills de Desenvolvimento toda segunda

1 email curto, só com as skills novas de Desenvolvimento. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Options Pattern for .NET Configuration

Overview

The Options pattern provides strongly-typed access to configuration groups:

  • IOptions<T> - Singleton, read once at startup
  • IOptionsSnapshot<T> - Scoped, reloads per request
  • IOptionsMonitor<T> - Singleton, real-time change notifications

Quick Reference

| Interface | Lifetime | Supports Reload | Named Options | Use Case | |-----------|----------|-----------------|---------------|----------| | IOptions<T> | Singleton | No | No | Static config | | IOptionsSnapshot<T> | Scoped | Yes | Yes | Request-scoped config | | IOptionsMonitor<T> | Singleton | Yes | Yes | Singleton services, change notifications |

Options Structure

/Application/Options/
├── DatabaseOptions.cs
├── JwtOptions.cs
├── CacheOptions.cs
├── EmailOptions.cs
└── FeatureFlagOptions.cs

Template: Basic Options Class

// src/{name}.application/Options/DatabaseOptions.cs
namespace {name}.application.options;

/// <summary>
/// Options classes should:
/// - Use the "Options" suffix
/// - Have public getters and setters
/// - Include validation via data annotations or IValidateOptions
/// </summary>
public sealed class DatabaseOptions
{
    /// <summary>
    /// Configuration section name in appsettings.json
    /// </summary>
    public const string SectionName = "Database";

    /// <summary>
    /// Connection string for the primary database
    /// </summary>
    public required string ConnectionString { get; set; }

    /// <summary>
    /// Maximum number of connections in the pool
    /// </summary>
    public int MaxPoolSize { get; set; } = 100;

    /// <summary>
    /// Minimum number of connections in the pool
    /// </summary>
    public int MinPoolSize { get; set; } = 5;

    /// <summary>
    /// Connection timeout in seconds
    /// </summary>
    public int ConnectionTimeout { get; set; } = 30;

    /// <summary>
    /// Enable connection pooling
    /// </summary>
    public bool EnablePooling { get; set; } = true;

    /// <summary>
    /// Enable query logging for debugging
    /// </summary>
    public bool EnableQueryLogging { get; set; } = false;
}

Corresponding appsettings.json

{
  "Database": {
    "ConnectionString": "Host=localhost;Database=mydb;Username=postgres;Password=secret",
    "MaxPoolSize": 100,
    "MinPoolSize": 5,
    "ConnectionTimeout": 30,
    "EnablePooling": true,
    "EnableQueryLogging": false
  }
}

Template: Options with Data Annotation Validation

// src/{name}.application/Options/JwtOptions.cs
using System.ComponentModel.DataAnnotations;

namespace {name}.application.options;

public sealed class JwtOptions
{
    public const string SectionName = "Jwt";

    [Required(ErrorMessage = "JWT Secret is required")]
    [MinLength(32, ErrorMessage = "JWT Secret must be at least 32 characters")]
    public required string Secret { get; set; }

    [Required(ErrorMessage = "JWT Issuer is required")]
    public required string Issuer { get; set; }

    [Required(ErrorMessage = "JWT Audience is required")]
    public required string Audience { get; set; }

    [Range(1, 1440, ErrorMessage = "Access token expiration must be between 1 and 1440 minutes")]
    public int AccessTokenExpirationMinutes { get; set; } = 15;

    [Range(1, 43200, ErrorMessage = "Refresh token expiration must be between 1 and 43200 minutes")]
    public int RefreshTokenExpirationMinutes { get; set; } = 10080; // 7 days
}

Template: Options with Custom Validation

// src/{name}.application/Options/CacheOptions.cs
namespace {name}.application.options;

public sealed class CacheOptions
{
    public const string SectionName = "Cache";

    public bool Enabled { get; set; } = true;
    public string? RedisConnectionString { get; set; }
    public int DefaultExpirationMinutes { get; set; } = 5;
    public int SlidingExpirationMinutes { get; set; } = 2;
    public string KeyPrefix { get; set; } = string.Empty;
}

// src/{name}.application/Options/Validation/CacheOptionsValidator.cs
using Microsoft.Extensions.Options;

namespace {name}.application.options.validation;

/// <summary>
/// Custom validation using IValidateOptions for complex rules
/// </summary>
public sealed class CacheOptionsValidator : IValidateOptions<CacheOptions>
{
    public ValidateOptionsResult Validate(string? name, CacheOptions options)
    {
        var failures = new List<string>();

        if (options.Enabled && string.IsNullOrWhiteSpace(options.RedisConnectionString))
        {
            failures.Add("RedisConnectionString is required when caching is enabled");
        }

        if (options.DefaultExpirationMinutes < 1)
        {
            failures.Add("DefaultExpirationMinutes must be at least 1");
        }

        if (options.SlidingExpirationMinutes >= options.DefaultExpirationMinutes)
        {
            failures.Add("SlidingExpirationMinutes must be less than DefaultExpirationMinutes");
        }

        return failures.Count > 0
            ? ValidateOptionsResult.Fail(failures)
            : ValidateOptionsResult.Success;
    }
}

Template: Registration in DependencyInjection

// src/{name}.application/DependencyInjection.cs
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using {name}.application.options;
using {name}.application.options.validation;

namespace {name}.application;

public static class DependencyInjection
{
    public static IServiceCollection AddApplication(
        this IServiceCollection services,
        IConfiguration configuration)
    {
        // ═══════════════════════════════════════════════════════════════
        // BASIC OPTIONS BINDING
        // ═══════════════════════════════════════════════════════════════
        services.Configure<DatabaseOptions>(
            configuration.GetSection(DatabaseOptions.SectionName));

        // ═══════════════════════════════════════════════════════════════
        // OPTIONS WITH DATA ANNOTATION VALIDATION
        // Validates at startup - fails fast if invalid
        // ═══════════════════════════════════════════════════════════════
        services.AddOptions<JwtOptions>()
            .Bind(configuration.GetSection(JwtOptions.SectionName))
            .ValidateDataAnnotations()
            .ValidateOnStart();  // Validates immediately at startup

        // ═══════════════════════════════════════════════════════════════
        // OPTIONS WITH CUSTOM VALIDATION
        // ═══════════════════════════════════════════════════════════════
        services.AddOptions<CacheOptions>()
            .Bind(configuration.GetSection(CacheOptions.SectionName))
            .ValidateDataAnnotations()
            .ValidateOnStart();

        services.AddSingleton<IValidateOptions<CacheOptions>, CacheOptionsValidator>();

        // ═══════════════════════════════════════════════════════════════
        // OPTIONS WITH POST-CONFIGURE
        // Modify options after binding
        // ═══════════════════════════════════════════════════════════════
        services.PostConfigure<DatabaseOptions>(options =>
        {
            // Apply environment-specific modifications
            if (string.IsNullOrEmpty(options.ConnectionString))
            {
                options.ConnectionString = Environment.GetEnvironmentVariable("DATABASE_URL")
                    ?? throw new InvalidOperationException("Database connection string not configured");
            }
        });

        return services;
    }
}

Template: Using IOptions<T> (Singleton Services)

// src/{name}.infrastructure/Services/JwtTokenService.cs
using Microsoft.Extensions.Options;
using {name}.application.options;

namespace {name}.infrastructure.services;

/// <summary>
/// Use IOptions<T> for:
/// - Singleton services
/// - Configuration that doesn't change at runtime
/// - Best performance (read once, cached forever)
///
Compartilhar X LinkedIn