C# Academy · Урок

Строго типизированные параметры с IOptions

Привязывайте разделы конфигурации к классам POCO с помощью IOptions , IOptionsSnapshot и IOptionsMonitor .

Урок 2 из 412 шагов

«Строго типизированные параметры с IOptions» — бесплатный урок C# Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.

Зачем нужны параметры со строгой типизацией?

Чтение config с помощью IConfiguration["Key"] возвращает нетипизированные строки. Шаблон параметров сопоставляет разделы конфигурации с классами C#, обеспечивая проверку на этапе компиляции, IntelliSense и поддержку валидации.

Определение класса параметров

Создайте обычный класс POCO, имена свойств которого соответствуют ключам JSON. По соглашению добавляйте статическую константу SectionName, указывающую на раздел config.

// 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
  }
}

Регистрация параметров

Вызовите Configure<T>, чтобы связать раздел конфигурации с классом параметров. Это регистрирует IOptions<T>, IOptionsSnapshot<T> и IOptionsMonitor<T> в 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 и IOptionsSnapshot и IOptionsMonitor

Существуют три варианта с разными сроками жизни и поведением при перезагрузке. Выберите подходящий для вашего сценария использования.

// 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);
}

Проверка параметров с помощью атрибутов

Пометьте свойства параметров атрибутами System.ComponentModel.DataAnnotations и вызовите ValidateDataAnnotations(), чтобы немедленно завершить запуск с ошибкой, если конфигурация недействительна.

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

Пользовательская проверка с помощью IValidateOptions

Для сложных правил, затрагивающих несколько свойств, реализуйте IValidateOptions<T>, чтобы получить полный программный контроль над логикой проверки.

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>();

Постконфигурация

PostConfigure выполняется после всех вызовов Configure и позволяет переопределять или вычислять значения — это полезно для вычисляемых свойств и настроек, зависящих от среды.

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

Именованные параметры

Если вам нужно несколько экземпляров одного типа параметров, например два SMTP-сервера, используйте именованные параметры, чтобы различать их.

// 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");
    }
}

Сокращённая запись BindConfiguration

Цепочка AddOptions().BindConfiguration() — это современный плавный способ одновременно зарегистрировать, связать, проверить параметры и немедленно завершить запуск при ошибке.

// 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();

Практический пример: параметры флагов функций

Полная настройка параметров флагов функций с поддержкой перезагрузки, позволяющая изменять переключатели в appsettings без повторного развертывания.

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");
}

Быстрая проверка

Какой вариант IOptions следует использовать в службе Singleton, которой необходимо отражать актуальные изменения конфигурации?

Итоги: параметры со строгой типизацией и IOptions

Основные выводы:

  • Шаблон параметров связывает разделы конфигурации с POCO через Configure<T> или AddOptions<T>().BindConfiguration()
  • IOptions<T>: Singleton, считывает данные один раз при запуске
  • IOptionsSnapshot<T>: Scoped, перезагружает данные для каждого запроса — не внедряйте его в Singleton
  • IOptionsMonitor<T>: безопасен для Singleton, предоставляет актуальное значение через CurrentValue и уведомления через OnChange
  • Проверяйте параметры с помощью DataAnnotations + ValidateDataAnnotations() + ValidateOnStart()
  • Используйте именованные параметры для нескольких экземпляров одного типа
Можно начать бесплатно

Изучай C# с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
93
Уроки
346

Часто задаваемые вопросы

Урок «Строго типизированные параметры с IOptions» бесплатный?

Да — полный текст урока «Строго типизированные параметры с IOptions» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.

Чему я научусь в уроке «Строго типизированные параметры с IOptions»?

Привязывайте разделы конфигурации к классам POCO с помощью IOptions , IOptionsSnapshot и IOptionsMonitor . Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Строго типизированные параметры с IOptions»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Источники и поставщики конфигурации
  2. Строго типизированные параметры с IOptions
  3. Проверка параметров и именованные параметры
  4. Управление секретами
← Назад к C# Academy