Маппинг настроек на класс

Получать доступ в приложении к настройками через ключи вида AppSettings:Versions:0:Number не очень удобно и надёжно. Для решения этой проблемы существует механизм переноса (маппинга/биндинга) конфигурации на объекты в коде.

Давайте попробуем воспользоваться им:

  1. В папке с нашими уроками введите команду:

    dotnet new console -o lesson09
    
  2. Заменим код Program.cs на:

    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.Hosting;
    
    using var host = Host.CreateDefaultBuilder(args).Build();
    var config = host.Services.GetService(typeof(IConfiguration)) as IConfiguration;
    
    var settings = new AppSettings();
    config!.GetSection(nameof(AppSettings)).Bind(settings);
    
    Console.WriteLine($"{settings.FirstWord} {settings.SecondWord} {settings.Versions[0].Number}");
    
  3. Добавим файл AppSettings.cs:

    public class AppSettings
    {
        public string? FirstWord { get; set; }
    
        public string? SecondWord { get; set; }
    
        public class Version
        {
            public int Number { get; set; }
        }
    
        public List<Version> Versions { get; set; } = new();
    }
    
  4. Создайте новый файл appsettings.json в том же каталоге, что и ваш файл Program.cs.

    {
        "AppSettings": {
            "FirstWord": "Hello",
            "SecondWord": "dotnet",
            "Versions": [
                {
                    "Number": 7
                }
            ]
        }
    }
    
  5. Создайте новый файл appsettings.Development.json в том же каталоге, что и ваш файл Program.cs.

    {
        "AppSettings": {
            "Versions": [
                {
                    "Number": 8
                }
            ]
        }
    }
    
  6. В консоле перейдите в папку с проектом.

  7. Установим зависимость через dotnet cli:

    dotnet add package Microsoft.Extensions.Hosting --version 7.0.1
    

    Добавление пакетов отразится в файле lesson09.csproj

  8. Вместо имени файла укажите шаблон appsettings*.json в csproj, все файлы подходящие под него будут копироваться в директорию при сборке проекта. Давайте добавим нужную настройку в lesson09.csproj.

    <ItemGroup>
      <Content Include="appsettings*.json">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      </Content>
    </ItemGroup>
    

    Должно получиться следующее:

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net7.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
      </PropertyGroup>
    
      <ItemGroup>
        <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
      </ItemGroup>
    
      <ItemGroup>
        <Content Include="appsettings*.json">
          <CopyToOutputDirectory>Always</CopyToOutputDirectory>
        </Content>
      </ItemGroup>
    
    </Project>
    

    В этом уроке мы описываем класс конфигурации и маппим (биндим) его на настройки конфигурацию приложения, затем используем получившийся инстанс класса в приложении для использования параметров конфигурации в приложении. На что тут стоит обратить внимание:

  9. Модификатор доступа public - указывает откуда будет доступен класс, говорит, что класс доступен всем.

    <aside> 🐩 Подробней про public можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/csharp/language-reference/keywords/public.

    </aside>

  10. Класс Version вложен в класс AppSettings. Так сделано по двум причинам: 1 - Version это часть класса AppSettings (доступ до него получился AppSettings.Version); 2 - размещать в одном файле два на одном уровне является не рекомендуемой практикой, а делать два файла и разносить фактически один объект в разные места не удобно в поддержке (к слову если бы AppSettings.Version находится в отдельном файле он бы назывался AppSettingsVersion).

    <aside> 🐩 Подробней про вложенные типы можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/csharp/programming-guide/classes-and-structs/nested-types.

    </aside>

  11. Ключевое слово class - говорит о том, что описываем тип является изменяемым ссылочным типом.

    <aside> 🐩 Подробней про class можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/csharp/fundamentals/types/classes.

    </aside>

  12. Оператор ? говорит о том, что значение допускает null, фактически делает тип ссылочным оборачивая его в контейнер System.Nullable<T>.

    <aside> 🐩 Подробней про class можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/csharp/language-reference/builtin-types/nullable-value-types.

    </aside>

  13. Ключевые слова get и set говорят о том, что поле является акцессором позволяющим как получать значение поля так и менять его.

    <aside> 🐩 Подробней про get и set можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/csharp/programming-guide/classes-and-structs/using-properties.

    </aside>

  14. Ключевое слово int является псевдонимом структуры Int32, говорит о том, что является типом значения, 32х битным целы числом, имеющее максимально возможное допустимое значение равное 2 147 483 647.

    <aside> 🐩 Подробней про структуры можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/csharp/language-reference/builtin-types/struct.

    </aside>

    <aside> 🐩 Подробней про целочисленные типы можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/csharp/language-reference/builtin-types/integral-numeric-types.

    </aside>

    <aside> 🐩 Подробней про int можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/api/system.int32?view=net-7.0.

    </aside>

  15. Универсальный (дженерик) класс List<T> это класс динамического списка, позволяющий задать какой именно тип хранится в элементах этого списка.

    <aside> 🐩 Подробней про универсальные типы можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/csharp/fundamentals/types/generics.

    </aside>

    <aside> 🐩 Подробней про List<T> можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/api/system.collections.generic.list-1?view=net-7.0.

    </aside>

  16. Выражение new в вариантах new AppSettings() и new() - конструируют новый экземпляр класса, в первом случае конструируемый класс задаётся явно, во втором вычисляется из левой части выражения.

    <aside> 🐩 Подробней про new можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/csharp/language-reference/operators/new-operator.

    </aside>

  17. Ключевое слово nameof - превращает имя типа переданного в функцию в строковую переменную, пример nameof(MyClass) вернёт строку “MyClass”.

    <aside> 🐩 Подробней про nameof можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/csharp/language-reference/operators/nameof.

    </aside>