12 февраля 2023

⚙️ Cпособы .NET конфигурации – IConfiguration

Архитектор ПО на .NET
Каждое приложение имеет несколько источников хранения настроек. Обсудим с вами, как читать данные из разных источников, группировать их для использования внутри приложения и как разбираться в конфигурации.
⚙️ Cпособы .NET конфигурации – IConfiguration

IConfiguration

IConfiguration — это набор свойств конфигурации приложения в виде пар «ключ — значение». Интерфейс IConfiguration может быть реализован для чтения из разных источников данных.

⚙️ Cпособы .NET конфигурации – IConfiguration

Конфигурация происходит путем указания, из каких источников стоит читать данные. При этом каждый поставщик конфигурации добавляет «слой» значений к ConfigurationBuilder. Метод Build() прочтет конфигурацию из указанного списка источников. Причем последовательность указания источников данных имеет значение. Каждый последующий источник переопределяет значение с таким же ключом, которое было в предыдущем источнике.

⚙️ Cпособы .NET конфигурации – IConfiguration

Для определения списка источников данных используется класс ConfigurationBuilder. Метод Build() прочтет данные и вернет объект IConfiguration, через который осуществляется доступ к данным.

При запуске приложения необходимо настроить чтение данных из разных источников. По умолчанию присутствует поддержка JSON, environments, CLI arguments и другие.

⚙️ Cпособы .NET конфигурации – IConfiguration

Например, указан такой порядок: AddJsonFile, затем AddEnvironmentsVariables, то вначале будут прочитаны данные из JSON-файла, а затем — переменных окружения. Если в переменной окружения есть какое-либо значение, то информация JSON-файла по ключу будет перезаписана. Метод Build() при этом возвращает IСonfiguration объект, который впоследствии можно использовать для чтения данных.

Непосредственно для чтения данных используем следующий код:

        public class MySettings
{
    public string AppName { get; set; }
    public int Port { get; set; }
    public string Host { get; set; }
}

// десериализовать всю секцию
var settings = configuration.GetRequiredSection("MySettings").Get<MySettings>();

// получить отдельное значение
var port = configuration.GetValue<int>("MySettings:Port");

// строку
var host = configuration["MySettings:Host"];
    

Что делать, если источник не стандартный?

Если ни один из доступных поставщиков данных вам не подходит, покажем, как реализовать настраиваемого поставщика данных. Например, использовать вашу базу данных или данные из объекта как источник конфигурации.

Создадим собственное расширение для чтения конфигурации. Специальный поставщик для чтения параметров из предоставленного Dictionary объекта.

  • Provider (чтение/запись данных)
        public class DictionaryConfigurationProvider : ConfigurationProvider
{
    private readonly IDictionary<string, string> _data;

    public DictionaryConfigurationProvider(IDictionary<string, string> data)
        => _data = data;
    
    public override void Load() => Data = _data;
}
    
  • Source (интеграция Provider и Builder)
        public class DictionaryConfigurationSource : IConfigurationSource
{
    private readonly IDictionary<string, string> _data;

    public DictionaryConfigurationSource(IDictionary<string, string> data) 
        => _data = data;
    
    public IConfigurationProvider Build(IConfigurationBuilder builder) 
        => new DictionaryConfigurationProvider(_data);
}
    
  • Расширение для IConfigurationBuilder
        public static class ConfigurationBuilderExtensions
{
    public static IConfigurationBuilder AddSimpleConfiguration(
    
    this IConfigurationBuilder builder, IDictionary<string, string> data)
    {
        data ??= new Dictionary<string, string>();
        return builder.Add(new DictionaryConfigurationSource(data));
    }
}
    
  • И последний шаг
        var data = new Dictionary<string, string>
{
{ "Hello", "World" }
};

var configuration = new ConfigurationBuilder()
    .AddSimpleConfiguration(data)
    .Build();

var who = configuration["Hello"];
Console.WriteLine($"Hello, {who}");

// ---
// Expected Result -> Hello, World
    

Продвинутая конфигурация для использования в тестах

Для проведения интеграционных или функциональных тестов часто приходится использовать реальное подключение к базе данных. Для этого подходит IConfiguration — делаем подстановку переменных (через environment variables) без необходимости сохранять данные в репозитории приложения.

Модульные тесты в Visual Studio можно настраивать с помощью файла .runsettings. Например, вы можете изменить версию .NET, на которой выполняются тесты, каталог для результатов тестирования или данные, которые собираются во время выполнения теста. Обычно файл .runsettings используется для настройки анализа покрытия кода.

Файлы параметров запуска можно использовать для настройки тестов, запускаемых из командной строки, из среды IDE или в рабочем процессе сборки с помощью Azure Test Plans или Team Foundation Server (TFS).

Файлы настроек запуска необязательны. Если вам не требуется особая конфигурация, вам также не нужен файл .runsettings.

  • Для использования продвинутой конфигурации в тестах создаем локальный файл .runsettings. Тут будет указана переменная окружения DB_CONNECTION_STRING, которая может быть прочитана при запусках тестов.
        <?xml version="1.0" encoding="utf-8"?>
<!-- File name extension must be .runsettings -->
<RunSettings>
    <RunConfiguration>
        <EnvironmentVariables>
            <DB_CONNECTION_STRING>
                Server=server;Database=db;Port=5432;UserId=user;Password=pass;
            </DB_CONNECTION_STRING>
        </EnvironmentVariables>
    </RunConfiguration>
</RunSettings>
    
  • Создаем путь к файлу через csproj

$(MSBuildProjectDirectory)\example.runsettings ...

  • ИЛИ указываем в IDE (в примере Rider)
⚙️ Cпособы .NET конфигурации – IConfiguration

Использование в тестах

        private const string DB_CS_ENV = "DB_CONNECTION_STRING";
private PostgresConnection _connection;

[OneTimeSetUp]
public void Setup()
{
    var config = new ConfigurationBuilder()
        .AddEnvironmentVariables()
        .Build();
    _connection = new PostgresConnection(config.GetSection(DB_CS_ENV).Value);
}

/*
HERE LOGIC FOR TESTS
...
*/
    

В качестве заключения

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

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека шарписта»

Комментарии

ВАКАНСИИ

Добавить вакансию
Разработчик C++
Москва, по итогам собеседования

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ