C# Academy · Lección

Options con tipos seguros mediante IOptions

Vincule secciones de configuración a clases POCO mediante IOptions , IOptionsSnapshot e IOptionsMonitor .

Lección 2 de 412 pasos

Options con tipos seguros mediante IOptions es una lección gratuita de C# Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C# Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C# Academy incluye 4 lecciones en total.

¿Por qué usar opciones fuertemente tipadas?

Leer la configuración con IConfiguration["Key"] devuelve cadenas sin tipo. El patrón Options asigna las secciones de configuración a clases de C#, lo que proporciona seguridad en tiempo de compilación, IntelliSense y compatibilidad con la validación.

Definición de una clase de opciones

Cree una clase POCO sencilla cuyos nombres de propiedad coincidan con sus claves JSON. Por convención, agregue una constante estática SectionName para identificar la sección de configuración.

// Configuration class
public class JwtOptions
{
    public const string SectionName = "Jwt";

    public string SecretKey { get; set; } = string.Empty;
    public string Issuer    { get; set; } = string.Empty;
    public string Audience  { get; set; } = string.Empty;
    public int    ExpiryMinutes { get; set; } = 60;
}

// appsettings.json:
{
  "Jwt": {
    "SecretKey": "my-very-secret-key",
    "Issuer": "https://myapp.com",
    "Audience": "https://myapp.com/api",
    "ExpiryMinutes": 120
  }
}

Registro de opciones

Llame a Configure<T> para vincular una sección de configuración a la clase de opciones. Esto registra IOptions<T>, IOptionsSnapshot<T> y IOptionsMonitor<T> en DI.

// Registration
builder.Services.Configure<JwtOptions>(
    builder.Configuration.GetSection(JwtOptions.SectionName));

// Alternative shorthand:
builder.Services
    .AddOptions<JwtOptions>()
    .BindConfiguration(JwtOptions.SectionName);

// Consuming via IOptions<T>:
public class TokenService
{
    private readonly JwtOptions _opts;

    public TokenService(IOptions<JwtOptions> opts)
        => _opts = opts.Value;

    public string CreateToken()
        => $"Issuer={_opts.Issuer}, Exp={_opts.ExpiryMinutes}m";
}

IOptions frente a IOptionsSnapshot e IOptionsMonitor

Existen tres variantes, con diferentes ciclos de vida y comportamientos de recarga. Elija la adecuada para su caso de uso.

// IOptions<T> — Singleton, reads config ONCE at startup
public class ApiClient(IOptions<ApiOptions> opts)
{
    private readonly ApiOptions _opts = opts.Value; // never changes
}

// IOptionsSnapshot<T> — Scoped, reloads per request
public class ReportService(IOptionsSnapshot<ReportOptions> opts)
{
    private readonly ReportOptions _opts = opts.Value; // fresh per request
}

// IOptionsMonitor<T> — Singleton, live updates + change notifications
public class FeatureService(IOptionsMonitor<FeatureFlags> monitor)
{
    public bool IsEnabled(string feature)
        => monitor.CurrentValue.EnabledFeatures.Contains(feature);
}

Validación de opciones con atributos

Decore las propiedades de las opciones con atributos de System.ComponentModel.DataAnnotations y llame a ValidateDataAnnotations() para que la aplicación falle rápidamente al iniciar si la configuración no es válida.

using System.ComponentModel.DataAnnotations;

public class SmtpOptions
{
    [Required]
    public string Host { get; set; } = string.Empty;

    [Range(1, 65535)]
    public int Port { get; set; } = 587;

    [Required, EmailAddress]
    public string FromAddress { get; set; } = string.Empty;
}

// Register with validation:
builder.Services
    .AddOptions<SmtpOptions>()
    .BindConfiguration("Smtp")
    .ValidateDataAnnotations()
    .ValidateOnStart(); // fail at startup, not first use

Validación personalizada con IValidateOptions

Para reglas complejas entre varias propiedades, implemente IValidateOptions<T> para obtener una lógica de validación programática completa.

public class JwtOptionsValidator : IValidateOptions<JwtOptions>
{
    public ValidateOptionsResult Validate(string? name, JwtOptions opts)
    {
        var errors = new List<string>();

        if (string.IsNullOrWhiteSpace(opts.SecretKey))
            errors.Add("SecretKey must not be empty");

        if (opts.SecretKey.Length < 32)
            errors.Add("SecretKey must be at least 32 characters");

        if (opts.ExpiryMinutes <= 0)
            errors.Add("ExpiryMinutes must be positive");

        return errors.Any()
            ? ValidateOptionsResult.Fail(errors)
            : ValidateOptionsResult.Success;
    }
}

builder.Services.AddSingleton<IValidateOptions<JwtOptions>, JwtOptionsValidator>();

Post-Configure

PostConfigure se ejecuta después de todas las llamadas a Configure y permite anular o derivar valores; resulta útil para propiedades calculadas o ajustes específicos del entorno.

builder.Services.Configure<CacheOptions>(
    builder.Configuration.GetSection("Cache"));

// Override in test environment:
builder.Services.PostConfigure<CacheOptions>(opts =>
{
    if (builder.Environment.IsEnvironment("Testing"))
    {
        opts.AbsoluteExpirationMinutes = 1; // very short in tests
        opts.UseDistributedCache = false;   // use in-memory cache
    }
});

// PostConfigure always runs LAST, even after AddOptions validators

Opciones con nombre

Cuando necesite varias instancias del mismo tipo de opciones, por ejemplo, dos servidores SMTP, use opciones con nombre para diferenciarlas.

// Register named options:
builder.Services.Configure<SmtpOptions>("Primary",
    builder.Configuration.GetSection("Smtp:Primary"));
builder.Services.Configure<SmtpOptions>("Backup",
    builder.Configuration.GetSection("Smtp:Backup"));

// Consume with IOptionsMonitor (supports named options):
public class EmailSender
{
    private readonly SmtpOptions _primary;
    private readonly SmtpOptions _backup;

    public EmailSender(IOptionsMonitor<SmtpOptions> monitor)
    {
        _primary = monitor.Get("Primary");
        _backup  = monitor.Get("Backup");
    }
}

Forma abreviada de BindConfiguration

La cadena AddOptions().BindConfiguration() es la forma moderna y fluida de registrar, vincular, validar y hacer que la aplicación falle rápidamente, todo en una sola expresión.

// Full registration chain:
builder.Services
    .AddOptions<DatabaseOptions>()
    .BindConfiguration("Database")          // bind section
    .ValidateDataAnnotations()               // attribute validation
    .Validate(opts =>                        // custom rule
        opts.MaxPoolSize >= opts.MinPoolSize,
        "MaxPoolSize must be >= MinPoolSize")
    .ValidateOnStart();                      // fail at startup

// Shorthand for simple cases:
builder.Services.AddOptions<AppOptions>()
    .BindConfiguration(AppOptions.SectionName)
    .ValidateOnStart();

Caso real: opciones de feature flags

Una configuración completa de opciones de feature flags con compatibilidad con la recarga, que permite cambiar los indicadores en appsettings sin volver a desplegar la aplicación.

public class FeatureFlags
{
    public bool EnableNewCheckout  { get; set; }
    public bool EnableAISearch     { get; set; }
    public bool EnableBetaDashboard { get; set; }
}

// appsettings.json:
// { "FeatureFlags": { "EnableNewCheckout": true, ... } }

builder.Services
    .AddOptions<FeatureFlags>()
    .BindConfiguration("FeatureFlags")
    .ValidateOnStart();

// In a controller or service:
public class CheckoutController : ControllerBase
{
    private readonly FeatureFlags _flags;

    public CheckoutController(IOptionsMonitor<FeatureFlags> m)
        => _flags = m.CurrentValue;

    [HttpGet("/checkout")]
    public IActionResult Index() =>
        _flags.EnableNewCheckout
            ? Ok("new checkout")
            : Ok("legacy checkout");
}

Comprobación rápida

¿Qué variante de IOptions debe usar en un servicio Singleton que necesita reflejar los cambios de configuración en tiempo real?

Resumen: opciones fuertemente tipadas con IOptions

Conclusiones clave:

  • El patrón Options vincula las secciones de configuración con POCO mediante Configure<T> o AddOptions<T>().BindConfiguration()
  • IOptions<T>: Singleton, se lee una vez al inicio
  • IOptionsSnapshot<T>: Scoped, se recarga en cada solicitud; no lo inyecte en Singletons
  • IOptionsMonitor<T>: seguro para Singletons, con CurrentValue y OnChange en tiempo real
  • Valide con DataAnnotations + ValidateDataAnnotations() + ValidateOnStart()
  • Use opciones con nombre para varias instancias del mismo tipo
Gratis para empezar

Aprende C# con un tutor de IA — gratis

Escribe y ejecuta código real en tu navegador, obtén ayuda instantánea de un tutor de IA disponible 24/7 y continúa donde lo dejaste en la web o en la aplicación.

Cursos
93
Lecciones
346

Preguntas frecuentes

¿La lección «Options con tipos seguros mediante IOptions» es gratis?

Sí — el texto completo de «Options con tipos seguros mediante IOptions» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C# Academy, actualiza a CoddyKit PRO. El curso de C# Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Options con tipos seguros mediante IOptions»?

Vincule secciones de configuración a clases POCO mediante IOptions , IOptionsSnapshot e IOptionsMonitor . Practicas C# Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar C# Academy?

No se requiere experiencia previa. C# Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.

¿Cuánto tiempo toma la lección «Options con tipos seguros mediante IOptions»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de C# Academy?

Sí. Cada lección de C# Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Orígenes y proveedores de configuración
  2. Options con tipos seguros mediante IOptions
  3. Validación de Options y Options con nombre
  4. Gestión de secretos
← Volver a C# Academy