Строго типизированные параметры с IOptions
Привязывайте разделы конфигурации к классам POCO с помощью IOptions , IOptionsSnapshot и IOptionsMonitor .
«Строго типизированные параметры с 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, перезагружает данные для каждого запроса — не внедряйте его в SingletonIOptionsMonitor<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 — локальная установка не требуется.
Все уроки этого курса
- Источники и поставщики конфигурации
- Строго типизированные параметры с IOptions
- Проверка параметров и именованные параметры
- Управление секретами