Проекция конфигурации на классы

При использовании разветвленной конфигурации приложения, например, в json-файлах с множеством параметров и секций бывает не всегда удобно использовать последовательный доступ к каждой настройке, используя индексатор IConfiguration. В ASP.NET Core может использоваться проекция конфигурации на классы C#, чтобы представить сложную иерархическую структуру конфигурации приложения в виде обычного объекта. Для этого мы можем использовать методы Get<T>() и Bind().

Пример использования методов Get<T>() и Bind()

До сих пор мы последовательно считывали необходимые нам настройки приложения используя свойство-индексатор IConfiguration. Создадим новый проект ASP.NET Core Web API и добавим в файл appsettings.json следующую конфигурацию:

{
  "Weather": {
    "Count": 3,
    "Min": 10,
    "Max": 30
  },
    "Logging": {
      "LogLevel": {
        "Default": "Information",
        "Microsoft.AspNetCore": "Warning"
      }
    },
    "AllowedHosts": "*"
  }

Секция Weather также содержит настройки для работы контроллера WeatherForecastController, но, в отличие от предыдущих примеров, здесь мы уже указываем три различных значения — Count, Min и Max. Теперь наша задача состоит в том, чтобы получить все три настройки из конфигурации. Для этого создадим новый класс со свойствами, соответствующими настройкам, например:

public class Options
{
    public int Count { get; set; }
    public int Min { get; set; }
    public int Max { get; set; }
}

Все три свойства этого класса публичные и соответствуют как по названию, так и по типу настройкам из конфигурации. Перейдем в контроллер  WeatherForecastController и изменим его код следующим образом:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    private readonly IConfiguration _config;

    public WeatherForecastController(IConfiguration configuration)
    {
        _config = configuration;
    }

    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        var options = _config.GetSection("Weather").Get<Options>(bindOpts=> { bindOpts.ErrorOnUnknownConfiguration = true; });

        return Enumerable.Range(1, options.Count).Select(index => new WeatherForecast
        {
            Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            TemperatureC = Random.Shared.Next(options.Min, options.Max),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        })
        .ToArray();
    }
}

Здесь мы запрашиваем через конструктор сервис IConfiguration, а в методе Get() в самом начале и происходит то, что называется «Проекция конфигурации на классы»

var options = _config.GetSection("Weather").Get<Options>(bindOpts=> 
{ 
    bindOpts.ErrorOnUnknownConfiguration = true; 
});

Здесь мы проецируем секцию «Weather» на класс Options. В параметрах метода мы указываем настройки привязки и, в данном случае, мы указываем, что необходимо , сгенерировать исключение при преобразовании значения или при обнаружении ключа конфигурации, для которого в предоставленном объекте модели нет свойства, совпадающего с именем ключа. В результате выполнения метода Get<T>() мы получаем уже готовый к использованию объект, который мы и используем далее для генерации массива объектов WeatherForecast. Запустим приложение и проверим результат:

 

Ещё один вариант проецирования конфигурации на класс – использование метода Bind(). Применительно к нашему примеру, проекция конфигурации на класс могла бы выглядеть следующим образом:

var options = new Options();
_config.GetSection("Weather").Bind(options, bindOpts => 
{ 
    bindOpts.ErrorOnUnknownConfiguration = true; 
});

То есть, в отличие от предыдущего метода, в метод Bind() мы передаем уже созданный объект. Также для метода Bind() имеется переопределенная версия, где мы можем сразу указать имя секции параметры которой необходимо спроецировать:

var options = new Options();
_config.Bind("Weather", options);

Привязка массива

Конфигурация может содержать в качестве настроек массив каких-либо значений. Чтобы определить массив значений в качестве настроек приложения, необходимо создать новую секцию с именем массива и расположить в этой секции необходимые настройки. Причем ключом настройки будет выступать порядковый номер элемента массива. Например, добавим в наш файл конфигурации следующий массив:

{
  "Weather": {
    "Count": 3,
    "Min": 10,
    "Max": 30,
    "Summaries": {
      "0": "Нормально",
      "1": "Тепло",
      "2": "Жарко",
      "3": "Духота",
      "4": "Адская жара"
    }
  },
    "Logging": {
      "LogLevel": {
        "Default": "Information",
        "Microsoft.AspNetCore": "Warning"
      }
    },
    "AllowedHosts": "*"
  }

Теперь изменим наш класс Options:

public class Options
{
    public int Count { get; set; }
    public int Min { get; set; }
    public int Max { get; set; }
    public string[] Summaries { get; set; }
}

И теперь воспользуемся массивом из конфигурации в нашем приложении:

[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
    var options = new Options();
    _config.Bind("Weather", options);
    
    return Enumerable.Range(1, options.Count).Select(index => new WeatherForecast
    {
        Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
        TemperatureC = Random.Shared.Next(options.Min, options.Max),
        Summary = options.Summaries[Random.Shared.Next(options.Summaries.Length)]
    })
    .ToArray();
}

Запустим приложение и убедимся. что теперь контроллер выдает значения на русском языке:

Итого

При необходимости, мы можем проецировать конфигурацию на обычные классы C#. Для проецирования конфигурации на классы используются два метода — универсальный метод Get<T>() и метод Bind(). Первый метод возвращает готовый к использованию объект, второй — требует предварительного создания объекта, на который будут проецироваться настройки из конфигурации.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии