0Pricing
C# Academy · Aula

Validação de Options e Options nomeadas

Valide Options na inicialização com DataAnnotations ou FluentValidation e use Options nomeadas para várias instâncias.

Validação de Options e Options nomeadas é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C# Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C# Academy inclui 4 aulas no total.

Por que validar opções?

Configurações ausentes ou malformadas causam erros em tempo de execução difíceis de rastrear. Validar as opções na inicialização transforma falhas silenciosas de configuração em exceções claras e descritivas antes que qualquer solicitação seja atendida.

ValidateOnStart

ValidateOnStart() aciona a validação imediatamente quando o aplicativo é iniciado, em vez de fazê-lo sob demanda no primeiro uso. Assim, uma implantação configurada incorretamente falha instantaneamente, e não horas depois.

builder.Services
    .AddOptions<DatabaseOptions>()
    .BindConfiguration("Database")
    .ValidateDataAnnotations()
    .ValidateOnStart(); // throw OptionsValidationException on startup

// Without ValidateOnStart:
// - Validation only runs on first IOptions<T>.Value access
// - A rarely-used service could run for hours before failing

// With ValidateOnStart:
// - App fails at Host.Run() if config is invalid
// - Health checks and probes never report healthy for bad config

Validação com DataAnnotations

Use os atributos padrão de System.ComponentModel.DataAnnotations na sua classe de opções. Eles são avaliados automaticamente por ValidateDataAnnotations().

using System.ComponentModel.DataAnnotations;

public class EmailOptions
{
    [Required(ErrorMessage = "SMTP host is required")]
    [MinLength(3)]
    public string SmtpHost { get; set; } = string.Empty;

    [Range(1, 65535, ErrorMessage = "Port must be 1-65535")]
    public int SmtpPort { get; set; } = 587;

    [Required]
    [EmailAddress(ErrorMessage = "Invalid sender address")]
    public string SenderAddress { get; set; } = string.Empty;

    [Range(1, 30)]
    public int TimeoutSeconds { get; set; } = 10;
}

builder.Services
    .AddOptions<EmailOptions>()
    .BindConfiguration("Email")
    .ValidateDataAnnotations()
    .ValidateOnStart();

Delegado de validação personalizado

A sobrecarga Validate(Func<T, bool>, string) adiciona uma expressão lambda para regras que não podem ser expressas com atributos, como restrições entre propriedades.

builder.Services
    .AddOptions<ConnectionPoolOptions>()
    .BindConfiguration("ConnectionPool")
    .ValidateDataAnnotations()
    .Validate(
        opts => opts.MaxSize >= opts.MinSize,
        "MaxSize must be greater than or equal to MinSize")
    .Validate(
        opts => opts.ConnectionTimeoutMs > 0,
        "ConnectionTimeoutMs must be positive")
    .ValidateOnStart();

public class ConnectionPoolOptions
{
    [Range(1, 100)] public int MinSize { get; set; } = 2;
    [Range(1, 500)] public int MaxSize { get; set; } = 20;
    public int ConnectionTimeoutMs { get; set; } = 5000;
}

IValidateOptions para regras complexas

Para lógica complexa com várias mensagens de erro, implemente IValidateOptions<T>. Ele recebe a instância de opções e retorna um resultado com mensagens detalhadas de falha.

public class PaymentOptionsValidator : IValidateOptions<PaymentOptions>
{
    public ValidateOptionsResult Validate(string? name, PaymentOptions opts)
    {
        var failures = new List<string>();

        if (opts.Provider == "Stripe" && string.IsNullOrWhiteSpace(opts.StripeSecretKey))
            failures.Add("StripeSecretKey is required when Provider is Stripe");

        if (opts.Provider == "PayPal" && string.IsNullOrWhiteSpace(opts.PayPalClientId))
            failures.Add("PayPalClientId is required when Provider is PayPal");

        if (opts.RetryCount < 0 || opts.RetryCount > 5)
            failures.Add("RetryCount must be between 0 and 5");

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

builder.Services.AddSingleton<IValidateOptions<PaymentOptions>, PaymentOptionsValidator>();

Opções nomeadas — conceito

As opções nomeadas permitem registrar várias configurações do mesmo tipo de opções. Um caso de uso comum é ter vários clientes HTTP de saída, cada um com URLs base e tempos limite diferentes.

// appsettings.json:
{
  "HttpClients": {
    "Orders": {
      "BaseUrl": "https://orders-service",
      "TimeoutSeconds": 30
    },
    "Inventory": {
      "BaseUrl": "https://inventory-service",
      "TimeoutSeconds": 10
    }
  }
}

public class HttpClientOptions
{
    public string BaseUrl { get; set; } = string.Empty;
    public int TimeoutSeconds { get; set; } = 30;
}

Registro de opções nomeadas

Passe uma cadeia de caracteres de nome como primeiro argumento para Configure<T>. Use IOptionsMonitor<T>.Get(name) para obter uma instância específica.

// Register:
builder.Services.Configure<HttpClientOptions>("Orders",
    builder.Configuration.GetSection("HttpClients:Orders"));
builder.Services.Configure<HttpClientOptions>("Inventory",
    builder.Configuration.GetSection("HttpClients:Inventory"));

// Consume:
public class ApiGateway
{
    private readonly HttpClientOptions _orders;
    private readonly HttpClientOptions _inventory;

    public ApiGateway(IOptionsMonitor<HttpClientOptions> monitor)
    {
        _orders    = monitor.Get("Orders");
        _inventory = monitor.Get("Inventory");
    }

    // IOptions<T>.Value always returns the unnamed (default) instance
    // IOptionsMonitor<T>.Get(name) returns the named instance
}

Opções nomeadas com validação

Valide as opções nomeadas individualmente chamando AddOptions<T>(name) para cada registro nomeado.

foreach (var clientName in new[] { "Orders", "Inventory", "Auth" })
{
    builder.Services
        .AddOptions<HttpClientOptions>(clientName)
        .BindConfiguration($"HttpClients:{clientName}")
        .ValidateDataAnnotations()
        .Validate(
            opts => Uri.IsWellFormedUriString(opts.BaseUrl, UriKind.Absolute),
            $"HttpClients:{clientName}:BaseUrl must be a valid absolute URI")
        .ValidateOnStart();
}

// If any named instance fails, the app refuses to start

API do OptionsBuilder

OptionsBuilder<T> (retornado por AddOptions<T>()) é a API fluente que encadeia de forma organizada todas as etapas de registro, associação e validação.

// Full OptionsBuilder chain:
builder.Services
    .AddOptions<DatabaseOptions>()        // create builder
    .BindConfiguration("Database")         // bind JSON section
    .Configure(opts =>                     // manual override
    {
        if (builder.Environment.IsDevelopment())
            opts.EnableDetailedErrors = true;
    })
    .PostConfigure(opts =>                 // runs after all Configure
    {
        opts.ConnectionString ??= "default-fallback";
    })
    .ValidateDataAnnotations()             // attribute rules
    .Validate(o => o.MaxPoolSize > 0,
              "MaxPoolSize must be positive")
    .ValidateOnStart();                    // eager validation

Exemplo do mundo real: opções de política de novas tentativas

Uma configuração completa de opções de novas tentativas, com validação entre campos e políticas nomeadas para diferentes serviços.

public class RetryOptions
{
    [Range(0, 10)] public int MaxAttempts { get; set; } = 3;
    [Range(100, 60000)] public int BaseDelayMs { get; set; } = 500;
    public bool UseExponentialBackoff { get; set; } = true;
    [Range(1, 120000)] public int MaxDelayMs { get; set; } = 30000;
}

foreach (var policy in new[] { "Database", "HttpClient", "MessageBus" })
{
    builder.Services
        .AddOptions<RetryOptions>(policy)
        .BindConfiguration($"RetryPolicies:{policy}")
        .Validate(o => !o.UseExponentialBackoff || o.MaxDelayMs > o.BaseDelayMs,
                  "MaxDelayMs must exceed BaseDelayMs when using exponential backoff")
        .ValidateOnStart();
}

Verificação rápida

Qual é o benefício de chamar ValidateOnStart() ao registrar opções?

Recapitulação: validação de opções e opções nomeadas

Principais conclusões:

  • ValidateOnStart(): falha na inicialização em vez de falhar no primeiro uso
  • DataAnnotations: [Required], [Range] etc. + ValidateDataAnnotations()
  • Validate(Func, message): expressão lambda embutida para regras entre propriedades
  • IValidateOptions<T>: validação programática completa com vários erros
  • Opções nomeadas: Configure<T>(name, ...) + IOptionsMonitor<T>.Get(name)
  • OptionsBuilder<T>: API fluente para encadear todas as etapas de registro

Perguntas Frequentes

A aula “Validação de Options e Options nomeadas” é grátis?

Sim — o texto completo de “Validação de Options e Options nomeadas” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C# Academy, atualize para CoddyKit PRO. O curso de C# Academy inclui 4 aulas no total.

O que vou aprender em “Validação de Options e Options nomeadas”?

Valide Options na inicialização com DataAnnotations ou FluentValidation e use Options nomeadas para várias instâncias. Você pratica C# Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar C# Academy?

Nenhuma experiência prévia é necessária. C# Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.

Quanto tempo leva a aula “Validação de Options e Options nomeadas”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de C# Academy?

Sim. Cada aula de C# Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Fontes e provedores de configuração
  2. Options fortemente tipadas com IOptions
  3. Validação de Options e Options nomeadas
  4. Gerenciamento de segredos
← Voltar para C# Academy