Готовая конфигурация

Корпорация Microsoft и open source сообщество сделали для нас уже готовую конфигурацию для консольных приложений включающую расширенную комплексную конфигурацию, а так же ряд дополнительных инфтсрументов.

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

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

    dotnet new console -o lesson08
    
  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 firstWord = config!["AppSettings:FirstWord"];
    var secondWord = config!["AppSettings:SecondWord"];
    var version = config!["AppSettings:Versions:0:Number"];
    
    Console.WriteLine($"{firstWord} {secondWord} {version}");
    
  3. Создайте новый файл appsettings.json в том же каталоге, что и ваш файл Program.cs.

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

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

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

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

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

  7. Вместо имени файла укажите шаблон appsettings*.json в csproj, все файлы подходящие под него будут копироваться в директорию при сборке проекта. Давайте добавим нужную настройку в lesson08.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>
    

    В этом уроке мы используем готовый шаблон проекта доступный через установленную зависимость Microsoft.Extensions.Hosting, она реализует всё, что мы делали в прошлом уроке сами и даже намного больше, но об этом уже в следующих уроках. На что тут стоит обратить внимание:

  8. Для использования статического метода CreateDefaultBuilder класс Host мы импорировали Microsoft.Extensions.Hosting.

  9. Мы использовали ключевое слово using перед var, это означает что объект возвращаемый методом Build объект реализует интерфейс IDisposable и после того как все ссылки на host пропадут, автоматически будет вызван метод Dispose объекта host.

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

    </aside>

    <aside> 🐕‍🦺 В целом про интерфейсы можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/csharp/language-reference/keywords/interface.

    </aside>

    <aside> 🐕‍🦺 Про интерфейс IDisposable можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/api/system.idisposable?view=net-7.0.

    </aside>

  10. Интерфейс IConfiguration это интерфейс объекта config который мы использовали последние несколько уроков (обычно мы заменяли его ключевым словом var и он вычислялся из правой стороны выражения).

    <aside> 🐕‍🦺 Про интерфейс IConfiguration можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/api/microsoft.extensions.configuration.iconfiguration?view=dotnet-plat-ext-7.0.

    </aside>

  11. Ключевое слово is приводи объект к типу если такое возможно иначе возвращает null и ключевое слово typeof - позволяет вернуть тип объекта по названию его класса или интерфейса.

    <aside> 🐕‍🦺 Подробней про ключевые слова is и typeof можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/csharp/language-reference/operators/type-testing-and-cast.

    </aside>

  12. Метод GetService возвращает объект по типу из провайдера добавленных в приложения сервисов.

  13. Оператор прощения null - ! в записи config!["AppSettings:Versions:0:Number"] подсказывает анализатору компилятора, что хоть и оператор as выше может вернуть config как null, но фактически такое не возможно, так как в Services всегда есть зарегистрированная реализация IConfiguration. В зависимости от настроек проекта в *.csporj отсутствие оператора ! может привести либо к предупреждению при сборке либо к ошибке во время сборки.

    <aside> 🐕‍🦺 Подробней про это можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/csharp/language-reference/compiler-messages/nullable-warnings#possible-dereference-of-null.

    </aside>

  14. Запустите приложение с полным набором параметров:

    DOTNET_ENVIRONMENT=Development \
    AppSettings__Versions__0__Number=9 \
    dotnet run AppSettings:Versions:0:Number=10
    
  15. Вы получите вывод:

    Hello dotnet 10

    Можете поэкспериментировать и удостовериться что всё работает так же как в уроке 7.

<aside> 🐕‍🦺 В этом уроке мы впервые познакомились с готовой конфигурацией консольных приложений. Она позволит нам иметь всю мощь комплексной конфигурации одной строчкой. Подробней про это можно почитать тут https://learn.microsoft.com/ru-ru/dotnet/core/extensions/configuration.

</aside>

<aside> 💡 Решение доступно тут https://github.com/vahpetr/lessions/tree/main/lesson08

</aside>