Конфигурация и логирование
Конфигурация и логирование: IConfiguration, IOptions и встроенный логгер.
Суть: конфигурация (строки подключения, настройки) и логирование тоже доступны через DI.
IConfigurationи типизированныйIOptions<T>дают доступ к настройкам, аILogger<T>— к структурированному логированию.
Хардкодить настройки в коде нельзя: разные окружения требуют разных значений, секреты нельзя коммитить. ASP.NET Core даёт единую систему конфигурации и логирования, доступную через те же механизмы DI, что и ваши сервисы.
Типизированная конфигурация
{
"Jwt": {
"Issuer": "myapp",
"ExpiryMinutes": 60
}
}
public class JwtOptions
{
public string Issuer { get; set; } = "";
public int ExpiryMinutes { get; set; }
}
// регистрация привязки секции к классу
builder.Services.Configure<JwtOptions>(
builder.Configuration.GetSection("Jwt"));
// использование через DI
public class TokenService
{
private readonly JwtOptions _opts;
public TokenService(IOptions<JwtOptions> opts) => _opts = opts.Value;
}
Вместо «магических строк» вроде обращения по ключу Jwt:Issuer вы получаете типизированный объект — с автодополнением и проверкой типов.
Логирование
public class UserService
{
private readonly ILogger<UserService> _log;
public UserService(ILogger<UserService> log) => _log = log;
public void Process(int id)
{
_log.LogInformation("Обработка пользователя {UserId}", id);
}
}
Обратите внимание на {UserId} — это структурированное логирование: значение пишется не просто в текст, а как именованное поле, по которому потом можно искать в системах логов.
Как работает под капотом
Конфигурация собирается из провайдеров (JSON-файлы, переменные окружения, аргументы) в единый IConfiguration, где более поздние источники переопределяют ранние. Configure<T> связывает секцию с классом и регистрирует IOptions<T> в контейнере. Логирование устроено как фабрика: ILogger<T> создаётся под конкретный класс T (имя категории равно имени класса), а сообщения уходят во все подключённые провайдеры (консоль, файлы, внешние системы).
Частые ошибки
- Доступ к настройкам строками везде. Обращение по строковым ключам по всему коду хрупко — типизируйте через
IOptions. - Логировать секреты и персональные данные. Пароли, токены, ПДн в логах — утечка.
- Строковая интерполяция в логах. Интерполяция значений ломает структурированность — используйте шаблоны вроде
{UserId}.
Best practices
- Группируйте настройки в классы Options и привязывайте секциями.
- Пишите структурированные логи с именованными параметрами — их можно фильтровать и агрегировать.
- Управляйте уровнями логов (Information/Warning/Error) через конфигурацию по окружениям.
Провайдеры конфигурации и приоритет источников
Конфигурация в ASP.NET Core — это не один файл, а композиция провайдеров, выстроенных в стопку: appsettings.json, затем appsettings.{Environment}.json, затем User Secrets (в Development), переменные окружения и аргументы командной строки. Все они сливаются в единый IConfiguration по принципу «последний побеждает»: значение из переменной окружения переопределит то же значение из JSON. Это даёт гибкость без правки кода: один и тот же образ контейнера в разных средах настраивается разными переменными.
Паттерн Options — рекомендуемый способ потреблять настройки. Вы описываете класс, привязываете секцию через Configure<T> и получаете типизированный объект. Есть варианты: IOptions<T> (значение фиксируется на старте), IOptionsSnapshot<T> (перечитывается на каждый запрос, удобно в Scoped), IOptionsMonitor<T> (реагирует на изменения в рантайме). Дополнительно можно валидировать настройки при старте, чтобы приложение падало сразу при кривой конфигурации, а не на первом запросе.
Зачем логи структурированные и как ими управлять
Разница между $"User {id} updated" и LogInformation("User {UserId} updated", id) огромна. Первый вариант — просто текст, второй — структурированная запись, где UserId сохраняется как отдельное поле. В системах сбора логов (Seq, Elasticsearch, Application Insights) по такому полю можно искать, фильтровать и строить дашборды: «покажи все события по UserId=42». Текст искать так нельзя. Поэтому в значениях логов используют именованные шаблоны, а не интерполяцию строк.
Логирование настраивается уровнями (Trace, Debug, Information, Warning, Error, Critical) и категориями (обычно имя класса через ILogger<T>). Через конфигурацию задают, какой уровень писать для каких категорий: в Development можно опуститься до Debug, в Production оставить Warning и выше, чтобы не захлёбываться в шуме. Отдельное правило безопасности: в логи никогда не пишут секреты, токены и персональные данные — лог часто доступен шире, чем сами данные, и утечка через него вполне реальна.
Итог: конфигурация и логирование — это сервисы, доступные через DI; IOptions даёт типобезопасные настройки, а ILogger — структурированные логи. Дальше — глубже разберём конвейер middleware.