Конфигурация в .NET Core

Авторы: Рик Андерсон (Rick Anderson) и Кирк Ларкин (Kirk Larkin)

Примечание

Это не последняя версия этой статьи. Чтобы перейти на последнюю версию, используйте селектор версии ASP.NET Core в верхней части оглавлиния.

Выбор версии

Если селектор не отображается в узком окне браузера, расширьте окно или щелкните вертикальное многоточие () >Оглавление.

Селектор оглавлиния

Настройка приложения в ASP.NET Core выполняется с помощью одного или нескольких поставщиков конфигурации. Поставщики конфигурации получают данные конфигурации в парах "ключ-значение" из различных источников:

  • файлов параметров, таких как appsettings.json ;
  • Переменные среды
  • Хранилище ключей Azure;
  • конфигурация приложения Azure;
  • аргументов командной строки;
  • пользовательские поставщики, установленные или созданные;
  • справочных файлов;
  • объектов .NET в памяти;

В этой статье приведены сведения о конфигурации в ASP.NET Core. Сведения об использовании конфигурации в консольных приложениях см. в статье Конфигурация .NET.

Конфигурация приложения и узла

Приложения ASP.NET Core настраивают и запускают узел. Узел отвечает за запуск приложения и управление временем существования. Шаблоны ASP.NET Core создают объект WebApplicationBuilder, содержащий узел. Хотя определенные настройки доступны в поставщиках конфигурации и узла, и приложения, как правило, нужно использовать конфигурацию узла только для необходимых ему настроек.

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

Источники конфигурации приложения по умолчанию

Веб-приложения ASP.NET Core, созданные с помощью dotnet new или Visual Studio, создают следующий код:

var builder = WebApplication.CreateBuilder(args);

WebApplication.CreateBuilder инициализирует новый экземпляр класса WebApplicationBuilder с предварительно настроенными значениями по умолчанию. Инициализированный экземпляр WebApplicationBuilder (builder) содержит конфигурацию по умолчанию для приложения с настройками в следующем порядке, от наиболее к наименее приоритетным:

  1. Аргументы командной строки, использующие поставщик конфигурации командной строки.
  2. Переменные среды без префикса, использующие соответствующий поставщик конфигурации.
  3. секреты пользователя, когда приложение выполняется в среде ;
  4. appsettings.{Environment}.json с использованием поставщика конфигурации JSON. Например, appsettings.Production.json и appsettings.Development.json.
  5. appsettings.json с использованием поставщика конфигурации JSON.
  6. Откат к конфигурации узла, описанной в следующем разделе.

Источники конфигурации узла по умолчанию

В следующем списке содержатся источники конфигурации узла по умолчанию от самого высокого до самого низкого приоритета для WebApplicationBuilder:

  1. Аргументы командной строки, использующие поставщик конфигурации командной строки.
  2. Переменные среды с префиксом DOTNET_, использующие поставщик конфигурации переменных среды.
  3. Переменные среды с префиксом ASPNETCORE_, использующие поставщик конфигурации переменных среды.

Для универсального узла ивеб-узла .NET источники конфигурации узла по умолчанию от самого высокого до самого низкого приоритета:

  1. Переменные среды с префиксом ASPNETCORE_, использующие поставщик конфигурации переменных среды.
  2. Аргументы командной строки, использующие поставщик конфигурации командной строки.
  3. Переменные среды с префиксом DOTNET_, использующие поставщик конфигурации переменных среды.

Если значение задано в конфигурации и узла, и приложения, то используется конфигурация приложения.

Переменные узла

Следующие переменные фиксируются на ранних этапах при инициализации построителей узлов и не затрагиваются конфигурацией приложения:

Все остальные параметры узла считываются не из конфигурации узла, а из конфигурации приложения.

URLS — один из множества стандартных параметров узла, не относящийся к начальной загрузке. Как и все параметры узла, не приведенные в списке выше, URLS считывается на более позднем этапе из конфигурации приложения. Конфигурация узла используется как страховочный вариант для конфигурации приложения, поэтому можно задать URLS в первой, но это будет переопределено любым источником в конфигурации приложения, например appsettings.json.

Подробнее см. раздел Изменение корневого каталога содержимого, имени приложения и среды, а также Изменение корневой папки содержимого, имени приложения и среды через переменные среды или командную строку.

Остальные разделы этой статьи относятся к конфигурации приложения.

Поставщики конфигурации приложения

В следующем коде отображаются включенные поставщики конфигурации в том порядке, в котором они были добавлены:

public class Index2Model : PageModel
{
    private IConfigurationRoot ConfigRoot;

    public Index2Model(IConfiguration configRoot)
    {
        ConfigRoot = (IConfigurationRoot)configRoot;
    }

    public ContentResult OnGet()
    {           
        string str = "";
        foreach (var provider in ConfigRoot.Providers.ToList())
        {
            str += provider.ToString() + "\n";
        }

        return Content(str);
    }
}

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

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

Дополнительные сведения о CreateBuilder см. в разделе Параметры сборщика по умолчанию.

appsettings.json

Рассмотрим следующий файл appsettings.json :

{
  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  },
  "MyKey": "My appsettings.json Value",
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

В следующем коде из примера загрузки отображаются некоторые из перечисленных выше параметров конфигурации:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

JsonConfigurationProvider по умолчанию загружает конфигурацию в следующем порядке:

  1. appsettings.json
  2. appsettings.{Environment}.json: например, файлы appsettings.Production.json и appsettings.Development.json. Версия среды файла загружается на основе IHostingEnvironment.EnvironmentName. Дополнительные сведения см. в статье Использование нескольких сред в ASP.NET Core.

Значения appsettings.{Environment}.json переопределяют ключи в файле appsettings.json. Например, по умолчанию:

  • В среде разработки конфигурация appsettings.Development.json переопределяет значения в файле appsettings.json.
  • В производственной среде конфигурация appsettings.Production.json переопределяет значения в файле appsettings.json. Например, при развертывании приложения в Azure.

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

С помощью конфигурации по умолчанию файлы appsettings.json и appsettings.{Environment}.json включаются с помощью reloadOnChange: true. Изменения, вносимые в файлы appsettings.json и appsettings.{Environment}.jsonпосле запуска приложения, считываются поставщиком конфигурации JSON.

Комментарии в appsettings.json

Комментарии в appsettings.json файлах и appsettings.{Environment}.jsonподдерживаются с помощью комментариев в стиле JavaScript или C#.

Привязка иерархических данных конфигурации с помощью шаблона параметров

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

  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  }

Создайте следующий класс PositionOptions:

public class PositionOptions
{
    public const string Position = "Position";

    public string Title { get; set; } = String.Empty;
    public string Name { get; set; } = String.Empty;
}

Класс параметров:

  • Должен быть неабстрактным с открытым конструктором без параметров.
  • Все открытые свойства чтения и записи типа привязаны.
  • Поля не привязаны. В приведенном выше коде свойство Position не привязано. Поле Position используется так, что строку "Position" не требуется жестко кодировать в приложении при привязке класса к поставщику конфигурации.

В приведенном ниже коде

  • Вызывает ConfigurationBinder.Bind для привязки класса PositionOptions к разделу Position.
  • Отображает данные конфигурации Position.
public class Test22Model : PageModel
{
    private readonly IConfiguration Configuration;

    public Test22Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var positionOptions = new PositionOptions();
        Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

В приведенном выше коде по умолчанию считываются изменения в файле конфигурации JSON, внесенные после запуска приложения.

ConfigurationBinder.Get<T> привязывает и возвращает указанный тип. Метод ConfigurationBinder.Get<T> может быть более удобным, чем ConfigurationBinder.Bind. В приведенном ниже примере кода демонстрируются способы использования ConfigurationBinder.Get<T> с классом PositionOptions:

public class Test21Model : PageModel
{
    private readonly IConfiguration Configuration;
    public PositionOptions? positionOptions { get; private set; }

    public Test21Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {            
        positionOptions = Configuration.GetSection(PositionOptions.Position)
                                                     .Get<PositionOptions>();

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

В приведенном выше коде по умолчанию считываются изменения в файле конфигурации JSON, внесенные после запуска приложения.

Альтернативный подход при использовании шаблона параметров — привязать раздел Position и добавить его в контейнер службы внедрения зависимостей. В следующем коде PositionOptions добавляется в контейнер службы с помощью интерфейса Configure и привязывается к конфигурации:

using ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<PositionOptions>(
    builder.Configuration.GetSection(PositionOptions.Position));

var app = builder.Build();

С помощью приведенного выше кода следующий код считывает параметры расположения:

public class Test2Model : PageModel
{
    private readonly PositionOptions _options;

    public Test2Model(IOptions<PositionOptions> options)
    {
        _options = options.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Title: {_options.Title} \n" +
                       $"Name: {_options.Name}");
    }
}

Приведенном выше кода изменения в файле конфигурации JSON, внесенные после запуска приложения, не считываются. Чтобы считать изменения после запуска приложения, используйте IOptionsSnapshot.

С помощью конфигурации по умолчанию файлы appsettings.json и appsettings.{Environment}.json включаются с помощью reloadOnChange: true. Изменения, вносимые в файлы appsettings.json и appsettings.{Environment}.jsonпосле запуска приложения, считываются поставщиком конфигурации JSON.

Сведения о добавлении дополнительных файлов конфигурации JSON см. в разделе Поставщик конфигурации JSON этого документа.

Объединение коллекций служб

Рассмотрим следующий код, который регистрирует службы и настраивает параметры:

using ConfigSample.Options;
using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<PositionOptions>(
    builder.Configuration.GetSection(PositionOptions.Position));
builder.Services.Configure<ColorOptions>(
    builder.Configuration.GetSection(ColorOptions.Color));

builder.Services.AddScoped<IMyDependency, MyDependency>();
builder.Services.AddScoped<IMyDependency2, MyDependency2>();

var app = builder.Build();

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

using ConfigSample.Options;
using Microsoft.Extensions.Configuration;

namespace Microsoft.Extensions.DependencyInjection
{
    public static class MyConfigServiceCollectionExtensions
    {
        public static IServiceCollection AddConfig(
             this IServiceCollection services, IConfiguration config)
        {
            services.Configure<PositionOptions>(
                config.GetSection(PositionOptions.Position));
            services.Configure<ColorOptions>(
                config.GetSection(ColorOptions.Color));

            return services;
        }

        public static IServiceCollection AddMyDependencyGroup(
             this IServiceCollection services)
        {
            services.AddScoped<IMyDependency, MyDependency>();
            services.AddScoped<IMyDependency2, MyDependency2>();

            return services;
        }
    }
}

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

using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddConfig(builder.Configuration)
    .AddMyDependencyGroup();

builder.Services.AddRazorPages();

var app = builder.Build();

Примечание. Каждый метод расширения services.Add{GROUP_NAME} добавляет и, возможно, настраивает службы. Например, AddControllersWithViews добавляет контроллеры MVC служб с необходимыми представлениями, а AddRazorPages — службы, требуемые для работы Razor Pages.

Безопасность и секреты пользователей

Рекомендации по данным конфигурации:

  • Никогда не храните пароли или другие конфиденциальные данные в коде поставщика конфигурации или в файлах конфигурации обычного текста. Хранить секреты во время разработки можно с помощью диспетчера секретов.
  • Не используйте секреты рабочей среды в средах разработки и тестирования.
  • Указывайте секреты вне проекта, чтобы их нельзя было случайно зафиксировать в репозитории с исходным кодом.

По умолчанию источник конфигурации пользовательских секретов регистрируется после источников конфигурации JSON. Таким образом, ключи секретов пользователя имеют приоритет над ключами в appsettings.json и appsettings.{Environment}.json.

Дополнительные сведения о хранении паролей или других конфиденциальных данных:

В Azure Key Vault безопасно хранятся секреты приложений ASP.NET Core. Дополнительные сведения см. в статье Поставщик конфигурации Azure Key Vault в ASP.NET Core.

Переменные среды без префикса

К переменным среды без префикса относятся те, что не имеют префикса ASPNETCORE_ или DOTNET_. Для примера можно привести набор шаблонов веб-приложения ASP.NET Core "ASPNETCORE_ENVIRONMENT": "Development" в launchSettings.json. Дополнительные сведения о переменных среды ASPNETCORE_ и DOTNET_:

При использовании конфигурации по умолчаниюEnvironmentVariablesConfigurationProvider загружает конфигурацию из пар "ключ — значение" в переменных среды после чтения appsettings.json, appsettings.{Environment}.json и секретов пользователя. Поэтому значения ключей, считанные из среды, переопределяют значения, считанные из appsettings.json, appsettings.{Environment}.json и секретов пользователя.

Разделитель : не работает с иерархическими ключами переменных среды на всех платформах. __ (двойной символ подчеркивания):

  • Поддерживается всеми платформами. Например, разделитель : не поддерживается Bash, а __ — поддерживается.
  • Автоматически заменяется на :

Следующие команды set:

set MyKey="My key from Environment"
set Position__Title=Environment_Editor
set Position__Name=Environment_Rick
dotnet run

Предыдущие параметры среды:

  • Задаются только в процессах, запускаемых из командного окна, в котором они были установлены.
  • Не будут считываться браузерами, запущенными в Visual Studio.

Следующие команды setx можно использовать для задания ключей и значений среды в Windows. В отличие от set, параметры setx сохраняются. /M задает переменную в системной среде. Если параметр /M не используется, задается переменная среды пользователя.

setx MyKey "My key from setx Environment" /M
setx Position__Title Environment_Editor /M
setx Position__Name Environment_Rick /M

Чтобы проверить, что предыдущие команды переопределяют appsettings.json и appsettings.{Environment}.json:

  • В Visual Studio: Выйдите из среды Visual Studio и перезапустите ее.
  • В CLI: Откройте новое командное окно и введите dotnet run.

Вызовите AddEnvironmentVariables со строкой, чтобы указать префикс для переменных среды:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Configuration.AddEnvironmentVariables(prefix: "MyCustomPrefix_");

var app = builder.Build();

В приведенном выше коде:

Префикс отделяется при создании пары конфигурации "ключ-значение".

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

set MyCustomPrefix_MyKey="My key with MyCustomPrefix_ Environment"
set MyCustomPrefix_Position__Title=Editor_with_customPrefix
set MyCustomPrefix_Position__Name=Environment_Rick_cp
dotnet run

Конфигурация по умолчанию загружает переменные среды и аргументы командной строки с префиксом DOTNET_ и ASPNETCORE_. Префиксы DOTNET_ и ASPNETCORE_ используются ASP.NET Core для конфигурации узла и приложения, но не для конфигурации пользователя. Дополнительные сведения о конфигурации узла и приложения см. в разделе Универсальный узел .NET.

В Службе приложений Azure выберите Новый параметр приложения на странице Параметры > Конфигурация. Параметры приложения Службы приложений Azure:

  • Шифруются, когда они неактивны, и передаются по зашифрованному каналу.
  • Предоставляются как переменные среды.

Дополнительные сведения см. в руководстве по переопределению конфигурации приложения Azure с помощью портала Azure.

Сведения о строках подключения к базе данных Azure см. в разделе Префиксы строк подключения.

Именование переменных среды

Имена переменных среды отражают структуру файла appsettings.json . Каждый элемент в иерархии отделяется двойным символом подчеркивания (предпочтительно) или двоеточием. Если структура элемента включает массив, индекс массива должен рассматриваться как дополнительное имя элемента в этом пути. Рассмотрим следующий файл appsettings.json и его эквивалентные значения, представленные в виде переменных среды:

appsettings.json

{
    "SmtpServer": "smtp.example.com",
    "Logging": [
        {
            "Name": "ToEmail",
            "Level": "Critical",
            "Args": {
                "FromAddress": "MySystem@example.com",
                "ToAddress": "SRE@example.com"
            }
        },
        {
            "Name": "ToConsole",
            "Level": "Information"
        }
    ]
}

Переменные среды

setx SmtpServer smtp.example.com
setx Logging__0__Name ToEmail
setx Logging__0__Level Critical
setx Logging__0__Args__FromAddress MySystem@example.com
setx Logging__0__Args__ToAddress SRE@example.com
setx Logging__1__Name ToConsole
setx Logging__1__Level Information

Переменные среды, заданные в созданном файле launchSettings.json

Переменные среды, заданные в launchSettings.json, переопределяют переменные, заданные в системной среде. Например, веб-шаблоны ASP.NET Core позволяют создать файл launchSettings.json, который задает следующую конфигурацию конечной точки:

"applicationUrl": "https://localhost:5001;http://localhost:5000"

При настройке applicationUrl устанавливается переменная среды ASPNETCORE_URLS и переопределяются значения, заданные в среде.

Экранирование переменных среды в Linux

В Linux значения переменных среды URL-адресов нужно экранировать, чтобы их можно было проанализировать с помощью systemd. Используйте средство Linux systemd-escape, которое приостанавливает http:--localhost:5001.

groot@terminus:~$ systemd-escape http://localhost:5001
http:--localhost:5001

Отображение переменных среды

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

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

foreach (var c in builder.Configuration.AsEnumerable())
{
    Console.WriteLine(c.Key + " = " + c.Value);
}

Командная строка

При использовании конфигурации по умолчаниюCommandLineConfigurationProvider загружает конфигурацию из пар "ключ-значение" аргументов командной строки после следующих источников конфигурации:

По умолчанию значения конфигурации, заданные для значений конфигурации переопределения в командной строке, задаются для всех остальных поставщиков конфигурации.

аргументов командной строки;

Следующая команда задает ключи и значения с помощью =:

dotnet run MyKey="Using =" Position:Title=Cmd Position:Name=Cmd_Rick

Следующая команда задает ключи и значения с помощью /:

dotnet run /MyKey "Using /" /Position:Title=Cmd /Position:Name=Cmd_Rick

Следующая команда задает ключи и значения с помощью --:

dotnet run --MyKey "Using --" --Position:Title=Cmd --Position:Name=Cmd_Rick

Значение ключа:

  • Должно соответствовать =, или ключ должен иметь префикс -- или /, когда значение следует за пробелом.
  • Является обязательным, если используется параметр =. Например, MySetting=.

В рамках одной и той же команды не смешивайте пары "ключ-значение" аргумента командной строки, которые используют = с парами "ключ-значение" с пробелом.

Сопоставления переключений

Сопоставление параметров позволяет указать логику замены имен ключей. Предоставьте словарь замены параметров для метода AddCommandLine.

В словаре сопоставлений переключений выполняется поиск ключа, который совпадает с ключом, предоставляемым аргументом командной строки. Если ключ в командной строке находится в словаре, значение словаря передается обратно, чтобы установить пару "ключ-значение" в конфигурацию приложения. Сопоставление переключений необходимо для любого ключа командной строки с префиксом из одного дефиса (-).

Правила ключей из словаря сопоставления переключений:

  • Параметры должны начинаться с - или --.
  • Словарь сопоставлений переключений не должен содержать повторяющиеся ключи.

Чтобы использовать словарь сопоставлений параметров, передайте его в вызов AddCommandLine:


var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

var switchMappings = new Dictionary<string, string>()
         {
             { "-k1", "key1" },
             { "-k2", "key2" },
             { "--alt3", "key3" },
             { "--alt4", "key4" },
             { "--alt5", "key5" },
             { "--alt6", "key6" },
         };

builder.Configuration.AddCommandLine(args, switchMappings);

var app = builder.Build();

Выполните следующую команду, чтобы проверить замену ключа:

dotnet run -k1 value1 -k2 value2 --alt3=value2 /alt4=value3 --alt5 value5 /alt6 value6

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

public class Test3Model : PageModel
{
    private readonly IConfiguration Config;

    public Test3Model(IConfiguration configuration)
    {
        Config = configuration;
    }

    public ContentResult OnGet()
    {
        return Content(
                $"Key1: '{Config["Key1"]}'\n" +
                $"Key2: '{Config["Key2"]}'\n" +
                $"Key3: '{Config["Key3"]}'\n" +
                $"Key4: '{Config["Key4"]}'\n" +
                $"Key5: '{Config["Key5"]}'\n" +
                $"Key6: '{Config["Key6"]}'");
    }
}

Для приложений, использующих сопоставления переключений, в вызове CreateDefaultBuilder аргументы передаваться не должны. Вызов команды AddCommandLine метода CreateDefaultBuilder не включает сопоставленные параметры, и нет возможности передать словарь сопоставления параметров в CreateDefaultBuilder. Чтобы решить эту проблему, нужно не передавать аргументы команде CreateDefaultBuilder, а позволить методу AddCommandLine метода ConfigurationBuilder обрабатывать как аргументы, так и словарь сопоставления параметров.

Настройка среды и аргументов командной строки с помощью Visual Studio

Аргументы среды и командной строки можно задать в Visual Studio в диалоговом окне профилей запуска:

  • В Обозревателе решений щелкните проект правой кнопкой мыши и выберите Свойства.
  • Откройте вкладку Отладка > Общие и выберите пункт Открыть пользовательский интерфейс профилей запуска отладки.

Иерархическая модель конфигурации

API конфигурации считывает иерархические данные конфигурации, выполняя преобразование в плоскую структуру иерархических данных с использованием разделителя в ключах конфигурации.

Пример скачивания содержит следующий файл appsettings.json:

{
  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  },
  "MyKey": "My appsettings.json Value",
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

В следующем коде из примера загрузки отображаются некоторые параметры конфигурации:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

Предпочтительный способ чтения иерархических данных конфигурации — использование шаблона параметров. Дополнительные сведения см. в разделе Привязка иерархических данных конфигурации в этом документе.

Методы GetSection и GetChildren доступны для изолирования разделов и дочерних элементов раздела в данных конфигурации. Эти методы описаны далее в разделе GetSection, GetChildren и Exists.

Ключи и значения конфигурации

Ключи конфигурации:

  • Не учитывают регистр. Например ConnectionString и connectionstring обрабатываются как эквивалентные ключи.
  • Если ключ и значение заданы в нескольких поставщиках конфигурации, используется значение из последнего добавленного поставщика. Дополнительные сведения см. в разделе Конфигурация по умолчанию.
  • Иерархические ключи
    • При взаимодействии с API конфигурации разделитель-двоеточие (:) поддерживается на всех платформах.
    • В переменных среды разделитель-двоеточие может не работать на всех платформах. Двойной знак подчеркивания (__) поддерживается на всех платформах и автоматически преобразовывается в двоеточие — :.
    • В Azure Key Vault иерархические ключи используют -- в качестве разделителя. Поставщик конфигурации Azure Key Vault автоматически заменяет -- на : при загрузке секретов в конфигурацию приложения.
  • ConfigurationBinder поддерживает массивы привязки к объектам с помощью массива индексов в ключах конфигурации. Привязка массива описана в разделе Привязка массива к классу.

Значения конфигурации:

  • Представляют собой строки.
  • Значение NULL не может храниться в конфигурации или быть привязанным к объектам.

Поставщики конфигурации

В следующей таблице показаны поставщики конфигурации, доступные для приложений ASP.NET Core.

Поставщик Предоставляет конфигурацию из
Поставщик конфигурации Azure Key Vault Хранилище ключей Azure;
Поставщик конфигурации приложения Azure конфигурация приложения Azure;
Поставщик конфигурации командной строки Параметры командной строки
Поставщик пользовательской конфигурации Источник пользователя
Поставщик конфигурации переменных среды Переменные среды
Поставщик конфигурации файла Файлы INI, JSON и XML
Поставщик конфигурации ключа для каждого файла справочных файлов;
Поставщик конфигурации памяти Коллекции оперативной памяти
Секреты пользователя Файл в каталоге профиля пользователя

Источники конфигурации считываются в том порядке, в котором указываются их поставщики конфигурации. Порядок поставщиков конфигурации в коде соответствует приоритетам ваших основных источников конфигурации, требуемых приложением.

Типичная последовательность поставщиков конфигурации.

  1. appsettings.json
  2. appsettings.{Environment}.json
  3. Секреты пользователя
  4. Переменные среды, использующие поставщик конфигурации переменных среды.
  5. Аргументы командной строки, использующие поставщик конфигурации командной строки.

Общепринятой практикой является добавление поставщика конфигурации командной строки последним в ряду поставщиков, чтобы аргументы командной строки могли переопределять конфигурацию, установленную другими поставщиками.

Предыдущая последовательность поставщиков используется в конфигурации по умолчанию.

Префиксы строк подключения

API конфигурации имеет особые правила обработки для четырех переменных среды строки подключения. Эти строки подключения участвуют в настройке строк подключения Azure для среды приложения. Переменные среды с префиксами, указанными в таблице, загружаются в приложение с конфигурацией по умолчанию или если префикс не предоставлен для AddEnvironmentVariables.

Префикс строки подключения Поставщик
CUSTOMCONNSTR_ Поставщик пользователя
MYSQLCONNSTR_ MySQL
SQLAZURECONNSTR_ База данных SQL Azure
SQLCONNSTR_ SQL Server

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

  • Ключ конфигурации создается путем удаления префикса переменных среды и добавления ключа раздела конфигурации (ConnectionStrings).
  • Создается новая пара "ключ — значение" конфигурации, которая представляет поставщика подключения базы данных (за исключением CUSTOMCONNSTR_, который не имеет указанного поставщика).
Ключ переменной среды Преобразованный ключ конфигурации Запись конфигурации поставщика
CUSTOMCONNSTR_{KEY} ConnectionStrings:{KEY} Запись конфигурации не создана.
MYSQLCONNSTR_{KEY} ConnectionStrings:{KEY} Ключ: ConnectionStrings:{KEY}_ProviderName:
Значение: MySql.Data.MySqlClient
SQLAZURECONNSTR_{KEY} ConnectionStrings:{KEY} Ключ: ConnectionStrings:{KEY}_ProviderName:
Значение: System.Data.SqlClient
SQLCONNSTR_{KEY} ConnectionStrings:{KEY} Ключ: ConnectionStrings:{KEY}_ProviderName:
Значение: System.Data.SqlClient

Поставщик конфигурации файла

FileConfigurationProvider является базовым классом для загрузки конфигурации из файловой системы. Следующие поставщики конфигурации являются производными от FileConfigurationProvider:

Поставщик конфигурации INI

IniConfigurationProvider загружает конфигурацию из пары "ключ — значение" INI-файла во время выполнения.

Следующий код добавляет несколько поставщиков конфигурации:

var builder = WebApplication.CreateBuilder(args);

builder.Configuration
    .AddIniFile("MyIniConfig.ini", optional: true, reloadOnChange: true)
    .AddIniFile($"MyIniConfig.{builder.Environment.EnvironmentName}.ini",
                optional: true, reloadOnChange: true);

builder.Configuration.AddEnvironmentVariables();
builder.Configuration.AddCommandLine(args);

builder.Services.AddRazorPages();

var app = builder.Build();

В приведенном выше коде параметры в файлах MyIniConfig.ini и MyIniConfig.{Environment}.ini переопределяются параметрами в следующих поставщиках:

Пример скачивания содержит следующий файл MyIniConfig.ini:

MyKey="MyIniConfig.ini Value"

[Position]
Title="My INI Config title"
Name="My INI Config name"

[Logging:LogLevel]
Default=Information
Microsoft=Warning

В следующем коде из примера загрузки отображаются некоторые из перечисленных выше параметров конфигурации:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

Поставщик конфигурации JSON

Поставщик JsonConfigurationProvider загружает конфигурацию из пар "ключ-значение" файла JSON.

Перегрузки могут указывать:

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

Рассмотрим следующий код.

using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddJsonFile("MyConfig.json",
        optional: true,
        reloadOnChange: true);

builder.Services.AddRazorPages();

var app = builder.Build();

Предыдущий код:

Как правило, не рекомендуется использовать специальный файл JSON, переопределяющий значения, заданные в поставщике конфигурации переменных среды и поставщике конфигурации командной строки.

Поставщик конфигурации XML

XmlConfigurationProvider загружает конфигурацию из пары "ключ — значение" XML-файла в среде выполнения.

Следующий код добавляет несколько поставщиков конфигурации:

var builder = WebApplication.CreateBuilder(args);

builder.Configuration
    .AddXmlFile("MyXMLFile.xml", optional: true, reloadOnChange: true)
    .AddXmlFile($"MyXMLFile.{builder.Environment.EnvironmentName}.xml",
                optional: true, reloadOnChange: true);

builder.Configuration.AddEnvironmentVariables();
builder.Configuration.AddCommandLine(args);

builder.Services.AddRazorPages();

var app = builder.Build();

В приведенном выше коде параметры в файлах MyXMLFile.xml и MyXMLFile.{Environment}.xml переопределяются параметрами в следующих поставщиках:

Пример скачивания содержит следующий файл MyXMLFile.xml:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <MyKey>MyXMLFile Value</MyKey>
  <Position>
    <Title>Title from  MyXMLFile</Title>
    <Name>Name from MyXMLFile</Name>
  </Position>
  <Logging>
    <LogLevel>
      <Default>Information</Default>
      <Microsoft>Warning</Microsoft>
    </LogLevel>
  </Logging>
</configuration>

В следующем коде из примера загрузки отображаются некоторые из перечисленных выше параметров конфигурации:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

Повторяющиеся элементы, использующие то же имя элемента, работают, если атрибут name используется для различения элементов.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <section name="section0">
    <key name="key0">value 00</key>
    <key name="key1">value 01</key>
  </section>
  <section name="section1">
    <key name="key0">value 10</key>
    <key name="key1">value 11</key>
  </section>
</configuration>

Следующий код считывает предыдущий файл конфигурации и отображает ключи и значения:

public class IndexModel : PageModel
{
    private readonly IConfiguration Configuration;

    public IndexModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var key00 = "section:section0:key:key0";
        var key01 = "section:section0:key:key1";
        var key10 = "section:section1:key:key0";
        var key11 = "section:section1:key:key1";

        var val00 = Configuration[key00];
        var val01 = Configuration[key01];
        var val10 = Configuration[key10];
        var val11 = Configuration[key11];

        return Content($"{key00} value: {val00} \n" +
                       $"{key01} value: {val01} \n" +
                       $"{key10} value: {val10} \n" +
                       $"{key10} value: {val11} \n"
                       );
    }
}

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

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <key attribute="value" />
  <section>
    <key attribute="value" />
  </section>
</configuration>

Предыдущий файл конфигурации загружает следующие ключи с помощью value.

  • key:attribute
  • section:key:attribute

Поставщик конфигурации ключа для каждого файла

KeyPerFileConfigurationProvider использует файлы каталога как пары "ключ — значение" конфигурации. Ключ является именем файла. Значение содержит содержимое файла. Поставщик конфигурации ключа для каждого файла используется в сценариях размещения Docker.

Чтобы активировать конфигурацию ключа для каждого файла, вызовите метод расширения AddKeyPerFile в экземпляре ConfigurationBuilder. Значение параметра directoryPath должно быть абсолютным путем к файлам.

Перегрузки позволяют указать следующее.

  • Action<KeyPerFileConfigurationSource> — делегат, который настраивает источник.
  • Обязательно ли указывать каталог и путь к каталогу.

Двойное подчеркивание (__) используется в качестве разделителя ключа конфигурации в именах файлов. Например, в имени файла Logging__LogLevel__System создается ключ конфигурации Logging:LogLevel:System.

Чтобы указать конфигурацию приложения, при сборке веб-узла вызовите ConfigureAppConfiguration.

.ConfigureAppConfiguration((hostingContext, config) =>
{
    var path = Path.Combine(
        Directory.GetCurrentDirectory(), "path/to/files");
    config.AddKeyPerFile(directoryPath: path, optional: true);
})

Поставщик конфигурации памяти

MemoryConfigurationProvider использует коллекцию памяти в качестве пар "ключ — значение" конфигурации.

Следующий код добавляет коллекцию памяти в систему конфигурации:

var builder = WebApplication.CreateBuilder(args);

var Dict = new Dictionary<string, string>
        {
           {"MyKey", "Dictionary MyKey Value"},
           {"Position:Title", "Dictionary_Title"},
           {"Position:Name", "Dictionary_Name" },
           {"Logging:LogLevel:Default", "Warning"}
        };

builder.Configuration.AddInMemoryCollection(Dict);
builder.Configuration.AddEnvironmentVariables();
builder.Configuration.AddCommandLine(args);

builder.Services.AddRazorPages();

var app = builder.Build();

В следующем коде из примера загрузки отображаются перечисленные выше параметры конфигурации:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

В предыдущем коде config.AddInMemoryCollection(Dict) добавляется после поставщиков конфигурации по умолчанию. Пример упорядочения поставщиков конфигурации см. в разделе Поставщик конфигурации JSON.

В разделе Привязка массива вы найдете еще один пример использования MemoryConfigurationProvider.

Конфигурация конечной точки Kestrel

Конфигурация конкретной конечной точки Kestrel переопределяет все межсерверные конфигурации конечной точки. Конфигурации межсерверных конечных точек включают:

Обратите внимание на следующий файл appsettings.json , используемый в веб-приложении ASP.NET Core:

{
  "Kestrel": {
    "Endpoints": {
      "Https": {
        "Url": "https://localhost:9999"
      }
    }
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
} 

Если предыдущая выделенная разметка используется в веб-приложении ASP.NET Core и приложение запускается в командной строке со следующей конфигурацией межсерверной конечной точки:

dotnet run --urls="https://localhost:7777"

Kestrel привязывается к конечной точке, настроенной специально для Kestrel в файле appsettings.json (https://localhost:9999), а не https://localhost:7777.

Рассмотрим конкретную конечную точку Kestrel, настроенную в качестве переменной среды:

set Kestrel__Endpoints__Https__Url=https://localhost:8888

В предыдущей переменной среды Https является именем конкретной конечной точки Kestrel. Предыдущий файл appsettings.json также определяет Kestrel конкретную конечную точку с именем Https. По умолчанию переменные среды, использующие поставщик конфигурации переменных среды считываются после appsettings.{Environment}.json. Поэтому для конечной точки Https используется предыдущая переменная среды.

GetValue

ConfigurationBinder.GetValue извлекает одно значение из конфигурации с указанным ключом и преобразует его в указанный тип:

public class TestNumModel : PageModel
{
    private readonly IConfiguration Configuration;

    public TestNumModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var number = Configuration.GetValue<int>("NumberKey", 99);
        return Content($"{number}");
    }
}

В приведенном выше коде, если NumberKey отсутствует в конфигурации, используется значение по умолчанию 99.

GetSection, GetChildren и Exists

В следующих примерах рассмотрим файл MySubsection.json.

{
  "section0": {
    "key0": "value00",
    "key1": "value01"
  },
  "section1": {
    "key0": "value10",
    "key1": "value11"
  },
  "section2": {
    "subsection0": {
      "key0": "value200",
      "key1": "value201"
    },
    "subsection1": {
      "key0": "value210",
      "key1": "value211"
    }
  }
}

Следующий код добавляет MySubsection.json к поставщикам конфигурации:

var builder = WebApplication.CreateBuilder(args);

builder.Configuration
    .AddJsonFile("MySubsection.json",
                 optional: true,
                 reloadOnChange: true);

builder.Services.AddRazorPages();

var app = builder.Build();

GetSection

IConfiguration.GetSection возвращает подраздел конфигурации с указанным ключом подраздела.

Следующий код возвращает значения для section1:

public class TestSectionModel : PageModel
{
    private readonly IConfiguration Config;

    public TestSectionModel(IConfiguration configuration)
    {
        Config = configuration.GetSection("section1");
    }

    public ContentResult OnGet()
    {
        return Content(
                $"section1:key0: '{Config["key0"]}'\n" +
                $"section1:key1: '{Config["key1"]}'");
    }
}

Следующий код возвращает значения для section2:subsection0:

public class TestSection2Model : PageModel
{
    private readonly IConfiguration Config;

    public TestSection2Model(IConfiguration configuration)
    {
        Config = configuration.GetSection("section2:subsection0");
    }

    public ContentResult OnGet()
    {
        return Content(
                $"section2:subsection0:key0 '{Config["key0"]}'\n" +
                $"section2:subsection0:key1:'{Config["key1"]}'");
    }
}

Значение GetSection никогда не возвращает значение null. Если соответствующий раздел не найден, возвращается пустой параметр IConfigurationSection.

Когда GetSection возвращает соответствующий раздел, Value не заполняется. Key и Path возвращаются, если раздел существует.

GetChildren и Exists

Следующий код вызывает IConfiguration.GetChildren и возвращает значения для section2:subsection0:

public class TestSection4Model : PageModel
{
    private readonly IConfiguration Config;

    public TestSection4Model(IConfiguration configuration)
    {
        Config = configuration;
    }

    public ContentResult OnGet()
    {
        string s = "";
        var selection = Config.GetSection("section2");
        if (!selection.Exists())
        {
            throw new Exception("section2 does not exist.");
        }
        var children = selection.GetChildren();

        foreach (var subSection in children)
        {
            int i = 0;
            var key1 = subSection.Key + ":key" + i++.ToString();
            var key2 = subSection.Key + ":key" + i.ToString();
            s += key1 + " value: " + selection[key1] + "\n";
            s += key2 + " value: " + selection[key2] + "\n";
        }
        return Content(s);
    }
}

Приведенный выше код вызывает ConfigurationExtensions.Exists для проверки существования раздела:

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

ConfigurationBinder.Bind поддерживает массивы привязки к объектам с помощью массива индексов в ключах конфигурации. Любой формат массива, который предоставляет сегмент числового ключа способен привязать массив к массиву класса POCO.

Рассмотрим MyArray.json из примера загрузки:

{
  "array": {
    "entries": {
      "0": "value00",
      "1": "value10",
      "2": "value20",
      "4": "value40",
      "5": "value50"
    }
  }
}

Следующий код добавляет MyArray.json к поставщикам конфигурации:

var builder = WebApplication.CreateBuilder(args);

builder.Configuration
    .AddJsonFile("MyArray.json",
                 optional: true,
                 reloadOnChange: true);

builder.Services.AddRazorPages();

var app = builder.Build();

Следующий код считывает конфигурацию и отображает значения:

public class ArrayModel : PageModel
{
    private readonly IConfiguration Config;
    public ArrayExample? _array { get; private set; }

    public ArrayModel(IConfiguration config)
    {
        Config = config;
    }

    public ContentResult OnGet()
    {
       _array = Config.GetSection("array").Get<ArrayExample>();
        if (_array == null)
        {
            throw new ArgumentNullException(nameof(_array));
        }
        string s = String.Empty;

        for (int j = 0; j < _array.Entries.Length; j++)
        {
            s += $"Index: {j}  Value:  {_array.Entries[j]} \n";
        }

        return Content(s);
    }
}
public class ArrayExample
{
    public string[]? Entries { get; set; } 
}

Предыдущий код возвращает следующие выходные данные:

Index: 0  Value: value00
Index: 1  Value: value10
Index: 2  Value: value20
Index: 3  Value: value40
Index: 4  Value: value50

В предыдущих выходных данных индекс 3 имеет значение value40, соответствующее "4": "value40", в файле MyArray.json. Индексы привязанного массива непрерывны и не привязаны к индексу ключа конфигурации. Модуль привязки конфигурации не поддерживает привязку значений NULL или создание записей NULL в связанных объектах.

Поставщик пользовательской конфигурации

Пример приложения демонстрирует, как создать базовый поставщик конфигурации, который считывает пары "ключ — значение" конфигурации из базы данных, используя Entity Framework (EF).

Поставщик имеет следующие характеристики.

  • База данных в памяти EF используется для демонстрационных целей. Чтобы использовать базу данных, для которой требуется строка подключения, выполните вторичный ConfigurationBuilder, чтобы предоставить строку подключения от другого поставщика конфигурации.
  • Поставщик считывает таблицу базы данных в конфигурации при запуске. Поставщик не запрашивает базу данных для каждого ключа.
  • Функция перезагрузки на изменение не реализована, поэтому обновление базы данных после запуска приложения не влияет на конфигурацию приложения.

Определите сущность EFConfigurationValue для хранения значений конфигурации в базе данных.

Models/EFConfigurationValue.cs:

public class EFConfigurationValue
{
    public string Id { get; set; } = String.Empty;
    public string Value { get; set; } = String.Empty;
}

Добавьте EFConfigurationContext в хранилище и обратитесь к настроенным значениям.

EFConfigurationProvider/EFConfigurationContext.cs:

public class EFConfigurationContext : DbContext
{
    public EFConfigurationContext(DbContextOptions<EFConfigurationContext> options) : base(options)
    {
    }

    public DbSet<EFConfigurationValue> Values => Set<EFConfigurationValue>();
}

Создайте класс, реализующий IConfigurationSource.

EFConfigurationProvider/EFConfigurationSource.cs:

public class EFConfigurationSource : IConfigurationSource
{
    private readonly Action<DbContextOptionsBuilder> _optionsAction;

    public EFConfigurationSource(Action<DbContextOptionsBuilder> optionsAction) => _optionsAction = optionsAction;

    public IConfigurationProvider Build(IConfigurationBuilder builder) => new EFConfigurationProvider(_optionsAction);
}

Создайте пользовательский поставщик конфигурации путем наследования от ConfigurationProvider. Поставщик конфигурации инициализирует пустую базу данных. Так как конфигурационные ключи не учитывают регистр, словарь, используемый для инициализации базы данных, создается с помощью функции сравнения без учета регистра (StringComparer.OrdinalIgnoreCase).

EFConfigurationProvider/EFConfigurationProvider.cs:

public class EFConfigurationProvider : ConfigurationProvider
{
    public EFConfigurationProvider(Action<DbContextOptionsBuilder> optionsAction)
    {
        OptionsAction = optionsAction;
    }

    Action<DbContextOptionsBuilder> OptionsAction { get; }

    public override void Load()
    {
        var builder = new DbContextOptionsBuilder<EFConfigurationContext>();

        OptionsAction(builder);

        using (var dbContext = new EFConfigurationContext(builder.Options))
        {
            if (dbContext == null || dbContext.Values == null)
            {
                throw new Exception("Null DB context");
            }
            dbContext.Database.EnsureCreated();

            Data = !dbContext.Values.Any()
                ? CreateAndSaveDefaultValues(dbContext)
                : dbContext.Values.ToDictionary(c => c.Id, c => c.Value);
        }
    }

    private static IDictionary<string, string> CreateAndSaveDefaultValues(
        EFConfigurationContext dbContext)
    {
        // Quotes (c)2005 Universal Pictures: Serenity
        // https://www.uphe.com/movies/serenity-2005
        var configValues =
            new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
            {
                    { "quote1", "I aim to misbehave." },
                    { "quote2", "I swallowed a bug." },
                    { "quote3", "You can't stop the signal, Mal." }
            };

        if (dbContext == null || dbContext.Values == null)
        {
            throw new Exception("Null DB context");
        }

        dbContext.Values.AddRange(configValues
            .Select(kvp => new EFConfigurationValue
            {
                Id = kvp.Key,
                Value = kvp.Value
            })
            .ToArray());

        dbContext.SaveChanges();

        return configValues;
    }
}

Метод расширения AddEFConfiguration позволяет добавить источник конфигурации к ConfigurationBuilder.

Extensions/EntityFrameworkExtensions.cs:

public static class EntityFrameworkExtensions
{
    public static IConfigurationBuilder AddEFConfiguration(
               this IConfigurationBuilder builder,
               Action<DbContextOptionsBuilder> optionsAction)
    {
        return builder.Add(new EFConfigurationSource(optionsAction));
    }
}

В следующем коде показано, как использовать пользовательский EFConfigurationProvider в Program.cs.

//using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddEFConfiguration(
    opt => opt.UseInMemoryDatabase("InMemoryDb"));

var app = builder.Build();

app.Run();

Конфигурация доступа с внедрением зависимостей (DI)

Конфигурацию можно внедрить в службы с помощью внедрения зависимостей (DI) путем разрешения службы IConfiguration:

public class Service
{
    private readonly IConfiguration _config;

    public Service(IConfiguration config) =>
        _config = config;

    public void DoSomething()
    {
        var configSettingValue = _config["ConfigSetting"];

        // ...
    }
}

Сведения о том, как получить доступ к значениям с помощью IConfiguration, см. в разделах GetValue и GetSection, GetChildren и Exists данной статьи.

Конфигурация доступа в RazorPages

В следующем коде отображаются данные конфигурации в RazorPage:

@page
@model Test5Model
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

Configuration value for 'MyKey': @Configuration["MyKey"]

В следующем коде MyOptions добавляется в контейнер службы с помощью интерфейса Configure и привязывается к конфигурации:

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<MyOptions>(
    builder.Configuration.GetSection("MyOptions"));

var app = builder.Build();

В следующей разметке для разрешения и вывода значений параметров используется директива @injectRazor.

@page
@model SampleApp.Pages.Test3Model
@using Microsoft.Extensions.Options
@using SampleApp.Models
@inject IOptions<MyOptions> optionsAccessor


<p><b>Option1:</b> @optionsAccessor.Value.Option1</p>
<p><b>Option2:</b> @optionsAccessor.Value.Option2</p>

Доступ к конфигурации в файле представления MVC

В следующем коде отображаются данные конфигурации в представлении MVC:

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

Configuration value for 'MyKey': @Configuration["MyKey"]

Доступ к конфигурации в Program.cs

Следующий код получает доступ к конфигурации в файле Program.cs.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

var key1 = app.Configuration.GetValue<int>("KeyOne");
var key2 = app.Configuration.GetValue<bool>("KeyTwo");

app.Logger.LogInformation($"KeyOne = {key1}");
app.Logger.LogInformation($"KeyTwo = {key2}");

app.Run();

Настройка параметров с помощью делегата

Параметры, настроенные в делегате, переопределяют значения, заданные в поставщиках конфигурации.

В приведенном ниже коде в контейнер службы добавляется служба IConfigureOptions<TOptions>. Она использует делегат для настройки значений для MyOptions:

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<MyOptions>(myOptions =>
{
    myOptions.Option1 = "Value configured in delegate";
    myOptions.Option2 = 500;
});

var app = builder.Build();

Следующий код отображает значения параметров:

public class Test2Model : PageModel
{
    private readonly IOptions<MyOptions> _optionsDelegate;

    public Test2Model(IOptions<MyOptions> optionsDelegate )
    {
        _optionsDelegate = optionsDelegate;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_optionsDelegate.Value.Option1} \n" +
                       $"Option2: {_optionsDelegate.Value.Option2}");
    }
}

В предыдущем примере значения Option1 и Option2 задаются в файле appsettings.json , а затем переопределяются настроенным делегатом.

Конфигурация узла и приложения

Перед настройкой и запуском приложения настройте и запустите узел. Узел отвечает за запуск приложения и управление временем существования. Как приложение, так и узел настраиваются с использованием поставщиков конфигурации, описанных в этом разделе. Пары "ключ — значение" конфигурации узлов также включаются в конфигурацию приложения. Дополнительные сведения о том, как используются поставщики конфигурации при создании узла и как источники конфигурации влияют на его настройку, см. в статье Основы ASP.NET Core.

Конфигурация узла по умолчанию

Подробные сведения о конфигурации по умолчанию при использовании веб-узла см. в разделе о версии ASP.NET Core 2.2 в этой статье.

  • Существуют следующие способы предоставления конфигурации узла.
  • Устанавливается конфигурация веб-узла по умолчанию (ConfigureWebHostDefaults):
    • Kestrel используется в качестве веб-сервера и настраивается посредством поставщиков конфигурации приложения.
    • Добавьте ПО промежуточного слоя фильтрации узлов.
    • Если переменной среды ASPNETCORE_FORWARDEDHEADERS_ENABLED присвоено значение true, добавьте ПО промежуточного слоя перенаправления заголовков.
    • Включите интеграцию служб IIS.

Другая конфигурация

Этот раздел относится только к конфигурации приложений. Другие аспекты запуска и размещения приложений ASP.NET Core настраиваются с помощью файлов конфигурации, которые не рассматриваются в этом разделе.

Переменные среды, заданные в launchSettings.json, переопределяют переменные, заданные в системной среде.

Дополнительные сведения о переносе конфигурации приложений из более ранних версий ASP.NET см. в статье Обновление с ASP.NET до ASP.NET Core.

Добавление конфигурации из внешней сборки

Реализация IHostingStartup позволяет при запуске добавлять в приложение улучшения из внешней сборки вне приложения класса Startup. Дополнительные сведения см. в статье Использование начальных сборок размещения в ASP.NET Core.

Дополнительные ресурсы

Настройка приложения в ASP.NET Core выполняется с помощью одного или нескольких поставщиков конфигурации. Поставщики конфигурации получают данные конфигурации в парах "ключ-значение" из различных источников:

  • файлов параметров, таких как appsettings.json ;
  • Переменные среды
  • Хранилище ключей Azure;
  • конфигурация приложения Azure;
  • аргументов командной строки;
  • пользовательские поставщики, установленные или созданные;
  • справочных файлов;
  • объектов .NET в памяти;

В этой статье приведены сведения о конфигурации в ASP.NET Core. Сведения об использовании конфигурации в консольных приложениях см. в статье Конфигурация .NET.

Конфигурация приложения и узла

Приложения ASP.NET Core настраивают и запускают узел. Узел отвечает за запуск приложения и управление временем существования. Шаблоны ASP.NET Core создают объект WebApplicationBuilder, содержащий узел. Хотя определенные настройки доступны в поставщиках конфигурации и узла, и приложения, как правило, нужно использовать конфигурацию узла только для необходимых ему настроек.

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

Источники конфигурации приложения по умолчанию

Веб-приложения ASP.NET Core, созданные с помощью dotnet new или Visual Studio, создают следующий код:

var builder = WebApplication.CreateBuilder(args);

WebApplication.CreateBuilder инициализирует новый экземпляр класса WebApplicationBuilder с предварительно настроенными значениями по умолчанию. Инициализированный экземпляр WebApplicationBuilder (builder) содержит конфигурацию по умолчанию для приложения с настройками в следующем порядке, от наиболее к наименее приоритетным:

  1. Аргументы командной строки, использующие поставщик конфигурации командной строки.
  2. Переменные среды без префикса, использующие соответствующий поставщик конфигурации.
  3. секреты пользователя, когда приложение выполняется в среде ;
  4. appsettings.{Environment}.json с использованием поставщика конфигурации JSON. Например, appsettings.Production.json и appsettings.Development.json.
  5. appsettings.json с использованием поставщика конфигурации JSON.
  6. Откат к конфигурации узла, описанной в следующем разделе.

Источники конфигурации узла по умолчанию

Следующий список содержит источники конфигурации узла по умолчанию от наиболее к наименее приоритетным:

  1. Переменные среды с префиксом ASPNETCORE_, использующие поставщик конфигурации переменных среды.
  2. Аргументы командной строки, использующие поставщик конфигурации командной строки.
  3. Переменные среды с префиксом DOTNET_, использующие поставщик конфигурации переменных среды.

Если значение задано в конфигурации и узла, и приложения, то используется конфигурация приложения.

См. пояснение в этом комментарии GitHub о том, почему в конфигурации узла переменные среды с префиксом ASPNETCORE_ имеют больший приоритет, чем аргументы командной строки.

Переменные узла

Следующие переменные фиксируются на ранних этапах при инициализации построителей узлов и не затрагиваются конфигурацией приложения:

Все остальные параметры узла считываются не из конфигурации узла, а из конфигурации приложения.

URLS — один из множества стандартных параметров узла, не относящийся к начальной загрузке. Как и все параметры узла, не приведенные в списке выше, URLS считывается на более позднем этапе из конфигурации приложения. Конфигурация узла используется как страховочный вариант для конфигурации приложения, поэтому можно задать URLS в первой, но это будет переопределено любым источником в конфигурации приложения, например appsettings.json.

Подробнее см. раздел Изменение корневого каталога содержимого, имени приложения и среды, а также Изменение корневой папки содержимого, имени приложения и среды через переменные среды или командную строку.

Остальные разделы этой статьи относятся к конфигурации приложения.

Поставщики конфигурации приложения

В следующем коде отображаются включенные поставщики конфигурации в том порядке, в котором они были добавлены:

public class Index2Model : PageModel
{
    private IConfigurationRoot ConfigRoot;

    public Index2Model(IConfiguration configRoot)
    {
        ConfigRoot = (IConfigurationRoot)configRoot;
    }

    public ContentResult OnGet()
    {           
        string str = "";
        foreach (var provider in ConfigRoot.Providers.ToList())
        {
            str += provider.ToString() + "\n";
        }

        return Content(str);
    }
}

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

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

Дополнительные сведения о CreateBuilder см. в разделе Параметры сборщика по умолчанию.

appsettings.json

Рассмотрим следующий файл appsettings.json :

{
  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  },
  "MyKey": "My appsettings.json Value",
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

В следующем коде из примера загрузки отображаются некоторые из перечисленных выше параметров конфигурации:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

JsonConfigurationProvider по умолчанию загружает конфигурацию в следующем порядке:

  1. appsettings.json
  2. appsettings.{Environment}.json: например, файлы appsettings.Production.json и appsettings.Development.json. Версия среды файла загружается на основе IHostingEnvironment.EnvironmentName. Дополнительные сведения см. в статье Использование нескольких сред в ASP.NET Core.

Значения appsettings.{Environment}.json переопределяют ключи в файле appsettings.json. Например, по умолчанию:

  • В среде разработки конфигурация appsettings.Development.json переопределяет значения в файле appsettings.json.
  • В производственной среде конфигурация appsettings.Production.json переопределяет значения в файле appsettings.json. Например, при развертывании приложения в Azure.

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

С помощью конфигурации по умолчанию файлы appsettings.json и appsettings.{Environment}.json включаются с помощью reloadOnChange: true. Изменения, вносимые в файлы appsettings.json и appsettings.{Environment}.jsonпосле запуска приложения, считываются поставщиком конфигурации JSON.

Привязка иерархических данных конфигурации с помощью шаблона параметров

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

  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  }

Создайте следующий класс PositionOptions:

public class PositionOptions
{
    public const string Position = "Position";

    public string Title { get; set; } = String.Empty;
    public string Name { get; set; } = String.Empty;
}

Класс параметров:

  • Должен быть неабстрактным с открытым конструктором без параметров.
  • Все открытые свойства чтения и записи типа привязаны.
  • Поля не привязаны. В приведенном выше коде свойство Position не привязано. Поле Position используется так, что строку "Position" не требуется жестко кодировать в приложении при привязке класса к поставщику конфигурации.

В приведенном ниже коде

  • Вызывает ConfigurationBinder.Bind для привязки класса PositionOptions к разделу Position.
  • Отображает данные конфигурации Position.
public class Test22Model : PageModel
{
    private readonly IConfiguration Configuration;

    public Test22Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var positionOptions = new PositionOptions();
        Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

В приведенном выше коде по умолчанию считываются изменения в файле конфигурации JSON, внесенные после запуска приложения.

ConfigurationBinder.Get<T> привязывает и возвращает указанный тип. Метод ConfigurationBinder.Get<T> может быть более удобным, чем ConfigurationBinder.Bind. В приведенном ниже примере кода демонстрируются способы использования ConfigurationBinder.Get<T> с классом PositionOptions:

public class Test21Model : PageModel
{
    private readonly IConfiguration Configuration;
    public PositionOptions? positionOptions { get; private set; }

    public Test21Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {            
        positionOptions = Configuration.GetSection(PositionOptions.Position)
                                                     .Get<PositionOptions>();

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

В приведенном выше коде по умолчанию считываются изменения в файле конфигурации JSON, внесенные после запуска приложения.

Альтернативный подход при использовании шаблона параметров — привязать раздел Position и добавить его в контейнер службы внедрения зависимостей. В следующем коде PositionOptions добавляется в контейнер службы с помощью интерфейса Configure и привязывается к конфигурации:

using ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<PositionOptions>(
    builder.Configuration.GetSection(PositionOptions.Position));

var app = builder.Build();

С помощью приведенного выше кода следующий код считывает параметры расположения:

public class Test2Model : PageModel
{
    private readonly PositionOptions _options;

    public Test2Model(IOptions<PositionOptions> options)
    {
        _options = options.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Title: {_options.Title} \n" +
                       $"Name: {_options.Name}");
    }
}

Приведенном выше кода изменения в файле конфигурации JSON, внесенные после запуска приложения, не считываются. Чтобы считать изменения после запуска приложения, используйте IOptionsSnapshot.

С помощью конфигурации по умолчанию файлы appsettings.json и appsettings.{Environment}.json включаются с помощью reloadOnChange: true. Изменения, вносимые в файлы appsettings.json и appsettings.{Environment}.jsonпосле запуска приложения, считываются поставщиком конфигурации JSON.

Сведения о добавлении дополнительных файлов конфигурации JSON см. в разделе Поставщик конфигурации JSON этого документа.

Объединение коллекций служб

Рассмотрим следующий код, который регистрирует службы и настраивает параметры:

using ConfigSample.Options;
using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<PositionOptions>(
    builder.Configuration.GetSection(PositionOptions.Position));
builder.Services.Configure<ColorOptions>(
    builder.Configuration.GetSection(ColorOptions.Color));

builder.Services.AddScoped<IMyDependency, MyDependency>();
builder.Services.AddScoped<IMyDependency2, MyDependency2>();

var app = builder.Build();

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

using ConfigSample.Options;
using Microsoft.Extensions.Configuration;

namespace Microsoft.Extensions.DependencyInjection
{
    public static class MyConfigServiceCollectionExtensions
    {
        public static IServiceCollection AddConfig(
             this IServiceCollection services, IConfiguration config)
        {
            services.Configure<PositionOptions>(
                config.GetSection(PositionOptions.Position));
            services.Configure<ColorOptions>(
                config.GetSection(ColorOptions.Color));

            return services;
        }

        public static IServiceCollection AddMyDependencyGroup(
             this IServiceCollection services)
        {
            services.AddScoped<IMyDependency, MyDependency>();
            services.AddScoped<IMyDependency2, MyDependency2>();

            return services;
        }
    }
}

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

using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddConfig(builder.Configuration)
    .AddMyDependencyGroup();

builder.Services.AddRazorPages();

var app = builder.Build();

Примечание. Каждый метод расширения services.Add{GROUP_NAME} добавляет и, возможно, настраивает службы. Например, AddControllersWithViews добавляет контроллеры MVC служб с необходимыми представлениями, а AddRazorPages — службы, требуемые для работы Razor Pages.

Безопасность и секреты пользователей

Рекомендации по данным конфигурации:

  • Никогда не храните пароли или другие конфиденциальные данные в коде поставщика конфигурации или в файлах конфигурации обычного текста. Хранить секреты во время разработки можно с помощью диспетчера секретов.
  • Не используйте секреты рабочей среды в средах разработки и тестирования.
  • Указывайте секреты вне проекта, чтобы их нельзя было случайно зафиксировать в репозитории с исходным кодом.

По умолчанию источник конфигурации пользовательских секретов регистрируется после источников конфигурации JSON. Таким образом, ключи секретов пользователя имеют приоритет над ключами в appsettings.json и appsettings.{Environment}.json.

Дополнительные сведения о хранении паролей или других конфиденциальных данных:

В Azure Key Vault безопасно хранятся секреты приложений ASP.NET Core. Дополнительные сведения см. в статье Поставщик конфигурации Azure Key Vault в ASP.NET Core.

Переменные среды без префикса

К переменным среды без префикса относятся те, что не имеют префикса ASPNETCORE_ или DOTNET_. Для примера можно привести набор шаблонов веб-приложения ASP.NET Core "ASPNETCORE_ENVIRONMENT": "Development" в launchSettings.json. Дополнительные сведения о переменных среды ASPNETCORE_ и DOTNET_:

При использовании конфигурации по умолчаниюEnvironmentVariablesConfigurationProvider загружает конфигурацию из пар "ключ — значение" в переменных среды после чтения appsettings.json, appsettings.{Environment}.json и секретов пользователя. Поэтому значения ключей, считанные из среды, переопределяют значения, считанные из appsettings.json, appsettings.{Environment}.json и секретов пользователя.

Разделитель : не работает с иерархическими ключами переменных среды на всех платформах. __ (двойной символ подчеркивания):

  • Поддерживается всеми платформами. Например, разделитель : не поддерживается Bash, а __ — поддерживается.
  • Автоматически заменяется на :

Следующие команды set:

set MyKey="My key from Environment"
set Position__Title=Environment_Editor
set Position__Name=Environment_Rick
dotnet run

Предыдущие параметры среды:

  • Задаются только в процессах, запускаемых из командного окна, в котором они были установлены.
  • Не будут считываться браузерами, запущенными в Visual Studio.

Следующие команды setx можно использовать для задания ключей и значений среды в Windows. В отличие от set, параметры setx сохраняются. /M задает переменную в системной среде. Если параметр /M не используется, задается переменная среды пользователя.

setx MyKey "My key from setx Environment" /M
setx Position__Title Environment_Editor /M
setx Position__Name Environment_Rick /M

Чтобы проверить, что предыдущие команды переопределяют appsettings.json и appsettings.{Environment}.json:

  • В Visual Studio: Выйдите из среды Visual Studio и перезапустите ее.
  • В CLI: Откройте новое командное окно и введите dotnet run.

Вызовите AddEnvironmentVariables со строкой, чтобы указать префикс для переменных среды:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Configuration.AddEnvironmentVariables(prefix: "MyCustomPrefix_");

var app = builder.Build();

В приведенном выше коде:

Префикс отделяется при создании пары конфигурации "ключ-значение".

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

set MyCustomPrefix_MyKey="My key with MyCustomPrefix_ Environment"
set MyCustomPrefix_Position__Title=Editor_with_customPrefix
set MyCustomPrefix_Position__Name=Environment_Rick_cp
dotnet run

Конфигурация по умолчанию загружает переменные среды и аргументы командной строки с префиксом DOTNET_ и ASPNETCORE_. Префиксы DOTNET_ и ASPNETCORE_ используются ASP.NET Core для конфигурации узла и приложения, но не для конфигурации пользователя. Дополнительные сведения о конфигурации узла и приложения см. в разделе Универсальный узел .NET.

В Службе приложений Azure выберите Новый параметр приложения на странице Параметры > Конфигурация. Параметры приложения Службы приложений Azure:

  • Шифруются, когда они неактивны, и передаются по зашифрованному каналу.
  • Предоставляются как переменные среды.

Дополнительные сведения см. в руководстве по переопределению конфигурации приложения Azure с помощью портала Azure.

Сведения о строках подключения к базе данных Azure см. в разделе Префиксы строк подключения.

Именование переменных среды

Имена переменных среды отражают структуру файла appsettings.json . Каждый элемент в иерархии отделяется двойным символом подчеркивания (предпочтительно) или двоеточием. Если структура элемента включает массив, индекс массива должен рассматриваться как дополнительное имя элемента в этом пути. Рассмотрим следующий файл appsettings.json и его эквивалентные значения, представленные в виде переменных среды:

appsettings.json

{
    "SmtpServer": "smtp.example.com",
    "Logging": [
        {
            "Name": "ToEmail",
            "Level": "Critical",
            "Args": {
                "FromAddress": "MySystem@example.com",
                "ToAddress": "SRE@example.com"
            }
        },
        {
            "Name": "ToConsole",
            "Level": "Information"
        }
    ]
}

Переменные среды

setx SmtpServer smtp.example.com
setx Logging__0__Name ToEmail
setx Logging__0__Level Critical
setx Logging__0__Args__FromAddress MySystem@example.com
setx Logging__0__Args__ToAddress SRE@example.com
setx Logging__1__Name ToConsole
setx Logging__1__Level Information

Переменные среды, заданные в созданном файле launchSettings.json

Переменные среды, заданные в launchSettings.json, переопределяют переменные, заданные в системной среде. Например, веб-шаблоны ASP.NET Core позволяют создать файл launchSettings.json, который задает следующую конфигурацию конечной точки:

"applicationUrl": "https://localhost:5001;http://localhost:5000"

При настройке applicationUrl устанавливается переменная среды ASPNETCORE_URLS и переопределяются значения, заданные в среде.

Экранирование переменных среды в Linux

В Linux значения переменных среды URL-адресов нужно экранировать, чтобы их можно было проанализировать с помощью systemd. Используйте средство Linux systemd-escape, которое приостанавливает http:--localhost:5001.

groot@terminus:~$ systemd-escape http://localhost:5001
http:--localhost:5001

Отображение переменных среды

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

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

foreach (var c in builder.Configuration.AsEnumerable())
{
    Console.WriteLine(c.Key + " = " + c.Value);
}

Командная строка

При использовании конфигурации по умолчаниюCommandLineConfigurationProvider загружает конфигурацию из пар "ключ-значение" аргументов командной строки после следующих источников конфигурации:

По умолчанию значения конфигурации, заданные для значений конфигурации переопределения в командной строке, задаются для всех остальных поставщиков конфигурации.

аргументов командной строки;

Следующая команда задает ключи и значения с помощью =:

dotnet run MyKey="Using =" Position:Title=Cmd Position:Name=Cmd_Rick

Следующая команда задает ключи и значения с помощью /:

dotnet run /MyKey "Using /" /Position:Title=Cmd /Position:Name=Cmd_Rick

Следующая команда задает ключи и значения с помощью --:

dotnet run --MyKey "Using --" --Position:Title=Cmd --Position:Name=Cmd_Rick

Значение ключа:

  • Должно соответствовать =, или ключ должен иметь префикс -- или /, когда значение следует за пробелом.
  • Является обязательным, если используется параметр =. Например, MySetting=.

В рамках одной и той же команды не смешивайте пары "ключ-значение" аргумента командной строки, которые используют = с парами "ключ-значение" с пробелом.

Сопоставления переключений

Сопоставление параметров позволяет указать логику замены имен ключей. Предоставьте словарь замены параметров для метода AddCommandLine.

В словаре сопоставлений переключений выполняется поиск ключа, который совпадает с ключом, предоставляемым аргументом командной строки. Если ключ в командной строке находится в словаре, значение словаря передается обратно, чтобы установить пару "ключ-значение" в конфигурацию приложения. Сопоставление переключений необходимо для любого ключа командной строки с префиксом из одного дефиса (-).

Правила ключей из словаря сопоставления переключений:

  • Параметры должны начинаться с - или --.
  • Словарь сопоставлений переключений не должен содержать повторяющиеся ключи.

Чтобы использовать словарь сопоставлений параметров, передайте его в вызов AddCommandLine:


var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

var switchMappings = new Dictionary<string, string>()
         {
             { "-k1", "key1" },
             { "-k2", "key2" },
             { "--alt3", "key3" },
             { "--alt4", "key4" },
             { "--alt5", "key5" },
             { "--alt6", "key6" },
         };

builder.Configuration.AddCommandLine(args, switchMappings);

var app = builder.Build();

Выполните следующую команду, чтобы проверить замену ключа:

dotnet run -k1 value1 -k2 value2 --alt3=value2 /alt4=value3 --alt5 value5 /alt6 value6

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

public class Test3Model : PageModel
{
    private readonly IConfiguration Config;

    public Test3Model(IConfiguration configuration)
    {
        Config = configuration;
    }

    public ContentResult OnGet()
    {
        return Content(
                $"Key1: '{Config["Key1"]}'\n" +
                $"Key2: '{Config["Key2"]}'\n" +
                $"Key3: '{Config["Key3"]}'\n" +
                $"Key4: '{Config["Key4"]}'\n" +
                $"Key5: '{Config["Key5"]}'\n" +
                $"Key6: '{Config["Key6"]}'");
    }
}

Для приложений, использующих сопоставления переключений, в вызове CreateDefaultBuilder аргументы передаваться не должны. Вызов команды AddCommandLine метода CreateDefaultBuilder не включает сопоставленные параметры, и нет возможности передать словарь сопоставления параметров в CreateDefaultBuilder. Чтобы решить эту проблему, нужно не передавать аргументы команде CreateDefaultBuilder, а позволить методу AddCommandLine метода ConfigurationBuilder обрабатывать как аргументы, так и словарь сопоставления параметров.

Настройка среды и аргументов командной строки с помощью Visual Studio

Аргументы среды и командной строки можно задать в Visual Studio в диалоговом окне профилей запуска:

  • В Обозревателе решений щелкните проект правой кнопкой мыши и выберите Свойства.
  • Откройте вкладку Отладка > Общие и выберите пункт Открыть пользовательский интерфейс профилей запуска отладки.

Иерархическая модель конфигурации

API конфигурации считывает иерархические данные конфигурации, выполняя преобразование в плоскую структуру иерархических данных с использованием разделителя в ключах конфигурации.

Пример скачивания содержит следующий файл appsettings.json:

{
  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  },
  "MyKey": "My appsettings.json Value",
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

В следующем коде из примера загрузки отображаются некоторые параметры конфигурации:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

Предпочтительный способ чтения иерархических данных конфигурации — использование шаблона параметров. Дополнительные сведения см. в разделе Привязка иерархических данных конфигурации в этом документе.

Методы GetSection и GetChildren доступны для изолирования разделов и дочерних элементов раздела в данных конфигурации. Эти методы описаны далее в разделе GetSection, GetChildren и Exists.

Ключи и значения конфигурации

Ключи конфигурации:

  • Не учитывают регистр. Например ConnectionString и connectionstring обрабатываются как эквивалентные ключи.
  • Если ключ и значение заданы более чем в одном поставщике конфигурации, используется значение из последнего добавленного поставщика. Дополнительные сведения см. в разделе Конфигурация по умолчанию.
  • Иерархические ключи
    • При взаимодействии с API конфигурации разделитель-двоеточие (:) поддерживается на всех платформах.
    • В переменных среды разделитель-двоеточие может не работать на всех платформах. Двойной знак подчеркивания (__) поддерживается на всех платформах и автоматически преобразовывается в двоеточие — :.
    • В Azure Key Vault иерархические ключи используют -- в качестве разделителя. Поставщик конфигурации Azure Key Vault автоматически заменяет -- на : при загрузке секретов в конфигурацию приложения.
  • ConfigurationBinder поддерживает массивы привязки к объектам с помощью массива индексов в ключах конфигурации. Привязка массива описана в разделе Привязка массива к классу.

Значения конфигурации:

  • Представляют собой строки.
  • Значение NULL не может храниться в конфигурации или быть привязанным к объектам.

Поставщики конфигурации

В следующей таблице показаны поставщики конфигурации, доступные для приложений ASP.NET Core.

Поставщик Предоставляет конфигурацию из
Поставщик конфигурации Azure Key Vault Хранилище ключей Azure;
Поставщик конфигурации приложения Azure конфигурация приложения Azure;
Поставщик конфигурации командной строки Параметры командной строки
Поставщик пользовательской конфигурации Источник пользователя
Поставщик конфигурации переменных среды Переменные среды
Поставщик конфигурации файла Файлы INI, JSON и XML
Поставщик конфигурации ключа для каждого файла справочных файлов;
Поставщик конфигурации памяти Коллекции оперативной памяти
Секреты пользователя Файл в каталоге профиля пользователя

Источники конфигурации считываются в том порядке, в котором указываются их поставщики конфигурации. Порядок поставщиков конфигурации в коде соответствует приоритетам ваших основных источников конфигурации, требуемых приложением.

Типичная последовательность поставщиков конфигурации.

  1. appsettings.json
  2. appsettings.{Environment}.json
  3. Секреты пользователя
  4. Переменные среды, использующие поставщик конфигурации переменных среды.
  5. Аргументы командной строки, использующие поставщик конфигурации командной строки.

Общепринятой практикой является добавление поставщика конфигурации командной строки последним в ряду поставщиков, чтобы аргументы командной строки могли переопределять конфигурацию, установленную другими поставщиками.

Предыдущая последовательность поставщиков используется в конфигурации по умолчанию.

Префиксы строк подключения

API конфигурации имеет особые правила обработки для четырех переменных среды строки подключения. Эти строки подключения участвуют в настройке строк подключения Azure для среды приложения. Переменные среды с префиксами, указанными в таблице, загружаются в приложение с конфигурацией по умолчанию или если префикс не предоставлен для AddEnvironmentVariables.

Префикс строки подключения Поставщик
CUSTOMCONNSTR_ Поставщик пользователя
MYSQLCONNSTR_ MySQL
SQLAZURECONNSTR_ База данных SQL Azure
SQLCONNSTR_ SQL Server

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

  • Ключ конфигурации создается путем удаления префикса переменных среды и добавления ключа раздела конфигурации (ConnectionStrings).
  • Создается новая пара "ключ — значение" конфигурации, которая представляет поставщика подключения базы данных (за исключением CUSTOMCONNSTR_, который не имеет указанного поставщика).
Ключ переменной среды Преобразованный ключ конфигурации Запись конфигурации поставщика
CUSTOMCONNSTR_{KEY} ConnectionStrings:{KEY} Запись конфигурации не создана.
MYSQLCONNSTR_{KEY} ConnectionStrings:{KEY} Ключ: ConnectionStrings:{KEY}_ProviderName:
Значение: MySql.Data.MySqlClient
SQLAZURECONNSTR_{KEY} ConnectionStrings:{KEY} Ключ: ConnectionStrings:{KEY}_ProviderName:
Значение: System.Data.SqlClient
SQLCONNSTR_{KEY} ConnectionStrings:{KEY} Ключ: ConnectionStrings:{KEY}_ProviderName:
Значение: System.Data.SqlClient

Поставщик конфигурации файла

FileConfigurationProvider является базовым классом для загрузки конфигурации из файловой системы. Следующие поставщики конфигурации являются производными от FileConfigurationProvider:

Поставщик конфигурации INI

IniConfigurationProvider загружает конфигурацию из пары "ключ — значение" INI-файла во время выполнения.

Следующий код добавляет несколько поставщиков конфигурации:

var builder = WebApplication.CreateBuilder(args);

builder.Configuration
    .AddIniFile("MyIniConfig.ini", optional: true, reloadOnChange: true)
    .AddIniFile($"MyIniConfig.{builder.Environment.EnvironmentName}.ini",
                optional: true, reloadOnChange: true);

builder.Configuration.AddEnvironmentVariables();
builder.Configuration.AddCommandLine(args);

builder.Services.AddRazorPages();

var app = builder.Build();

В приведенном выше коде параметры в файлах MyIniConfig.ini и MyIniConfig.{Environment}.ini переопределяются параметрами в следующих поставщиках:

Пример скачивания содержит следующий файл MyIniConfig.ini:

MyKey="MyIniConfig.ini Value"

[Position]
Title="My INI Config title"
Name="My INI Config name"

[Logging:LogLevel]
Default=Information
Microsoft=Warning

В следующем коде из примера загрузки отображаются некоторые из перечисленных выше параметров конфигурации:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

Поставщик конфигурации JSON

Поставщик JsonConfigurationProvider загружает конфигурацию из пар "ключ-значение" файла JSON.

Перегрузки могут указывать:

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

Рассмотрим следующий код.

using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddJsonFile("MyConfig.json",
        optional: true,
        reloadOnChange: true);

builder.Services.AddRazorPages();

var app = builder.Build();

Предыдущий код:

Как правило, не рекомендуется использовать специальный файл JSON, переопределяющий значения, заданные в поставщике конфигурации переменных среды и поставщике конфигурации командной строки.

Поставщик конфигурации XML

XmlConfigurationProvider загружает конфигурацию из пары "ключ — значение" XML-файла в среде выполнения.

Следующий код добавляет несколько поставщиков конфигурации:

var builder = WebApplication.CreateBuilder(args);

builder.Configuration
    .AddXmlFile("MyXMLFile.xml", optional: true, reloadOnChange: true)
    .AddXmlFile($"MyXMLFile.{builder.Environment.EnvironmentName}.xml",
                optional: true, reloadOnChange: true);

builder.Configuration.AddEnvironmentVariables();
builder.Configuration.AddCommandLine(args);

builder.Services.AddRazorPages();

var app = builder.Build();

В приведенном выше коде параметры в файлах MyXMLFile.xml и MyXMLFile.{Environment}.xml переопределяются параметрами в следующих поставщиках:

Пример скачивания содержит следующий файл MyXMLFile.xml:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <MyKey>MyXMLFile Value</MyKey>
  <Position>
    <Title>Title from  MyXMLFile</Title>
    <Name>Name from MyXMLFile</Name>
  </Position>
  <Logging>
    <LogLevel>
      <Default>Information</Default>
      <Microsoft>Warning</Microsoft>
    </LogLevel>
  </Logging>
</configuration>

В следующем коде из примера загрузки отображаются некоторые из перечисленных выше параметров конфигурации:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

Повторяющиеся элементы, использующие то же имя элемента, работают, если атрибут name используется для различения элементов.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <section name="section0">
    <key name="key0">value 00</key>
    <key name="key1">value 01</key>
  </section>
  <section name="section1">
    <key name="key0">value 10</key>
    <key name="key1">value 11</key>
  </section>
</configuration>

Следующий код считывает предыдущий файл конфигурации и отображает ключи и значения:

public class IndexModel : PageModel
{
    private readonly IConfiguration Configuration;

    public IndexModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var key00 = "section:section0:key:key0";
        var key01 = "section:section0:key:key1";
        var key10 = "section:section1:key:key0";
        var key11 = "section:section1:key:key1";

        var val00 = Configuration[key00];
        var val01 = Configuration[key01];
        var val10 = Configuration[key10];
        var val11 = Configuration[key11];

        return Content($"{key00} value: {val00} \n" +
                       $"{key01} value: {val01} \n" +
                       $"{key10} value: {val10} \n" +
                       $"{key10} value: {val11} \n"
                       );
    }
}

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

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <key attribute="value" />
  <section>
    <key attribute="value" />
  </section>
</configuration>

Предыдущий файл конфигурации загружает следующие ключи с помощью value.

  • key:attribute
  • section:key:attribute

Поставщик конфигурации ключа для каждого файла

KeyPerFileConfigurationProvider использует файлы каталога как пары "ключ — значение" конфигурации. Ключ является именем файла. Значение содержит содержимое файла. Поставщик конфигурации ключа для каждого файла используется в сценариях размещения Docker.

Чтобы активировать конфигурацию ключа для каждого файла, вызовите метод расширения AddKeyPerFile в экземпляре ConfigurationBuilder. Значение параметра directoryPath должно быть абсолютным путем к файлам.

Перегрузки позволяют указать следующее.

  • Action<KeyPerFileConfigurationSource> — делегат, который настраивает источник.
  • Обязательно ли указывать каталог и путь к каталогу.

Двойное подчеркивание (__) используется в качестве разделителя ключа конфигурации в именах файлов. Например, в имени файла Logging__LogLevel__System создается ключ конфигурации Logging:LogLevel:System.

Чтобы указать конфигурацию приложения, при сборке веб-узла вызовите ConfigureAppConfiguration.

.ConfigureAppConfiguration((hostingContext, config) =>
{
    var path = Path.Combine(
        Directory.GetCurrentDirectory(), "path/to/files");
    config.AddKeyPerFile(directoryPath: path, optional: true);
})

Поставщик конфигурации памяти

MemoryConfigurationProvider использует коллекцию памяти в качестве пар "ключ — значение" конфигурации.

Следующий код добавляет коллекцию памяти в систему конфигурации:

var builder = WebApplication.CreateBuilder(args);

var Dict = new Dictionary<string, string>
        {
           {"MyKey", "Dictionary MyKey Value"},
           {"Position:Title", "Dictionary_Title"},
           {"Position:Name", "Dictionary_Name" },
           {"Logging:LogLevel:Default", "Warning"}
        };

builder.Configuration.AddInMemoryCollection(Dict);
builder.Configuration.AddEnvironmentVariables();
builder.Configuration.AddCommandLine(args);

builder.Services.AddRazorPages();

var app = builder.Build();

В следующем коде из примера загрузки отображаются перечисленные выше параметры конфигурации:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

В предыдущем коде config.AddInMemoryCollection(Dict) добавляется после поставщиков конфигурации по умолчанию. Пример упорядочения поставщиков конфигурации см. в разделе Поставщик конфигурации JSON.

В разделе Привязка массива вы найдете еще один пример использования MemoryConfigurationProvider.

Конфигурация конечной точки Kestrel

Конфигурация конкретной конечной точки Kestrel переопределяет все межсерверные конфигурации конечной точки. Конфигурации межсерверных конечных точек включают:

Обратите внимание на следующий файл appsettings.json , используемый в веб-приложении ASP.NET Core:

{
  "Kestrel": {
    "Endpoints": {
      "Https": {
        "Url": "https://localhost:9999"
      }
    }
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
} 

Если предыдущая выделенная разметка используется в веб-приложении ASP.NET Core и приложение запускается в командной строке со следующей конфигурацией межсерверной конечной точки:

dotnet run --urls="https://localhost:7777"

Kestrel привязывается к конечной точке, настроенной специально для Kestrel в файле appsettings.json (https://localhost:9999), а не https://localhost:7777.

Рассмотрим конкретную конечную точку Kestrel, настроенную в качестве переменной среды:

set Kestrel__Endpoints__Https__Url=https://localhost:8888

В предыдущей переменной среды Https является именем конкретной конечной точки Kestrel. Предыдущий файл appsettings.json также определяет Kestrel конкретную конечную точку с именем Https. По умолчанию переменные среды, использующие поставщик конфигурации переменных среды считываются после appsettings.{Environment}.json. Поэтому для конечной точки Https используется предыдущая переменная среды.

GetValue

ConfigurationBinder.GetValue извлекает одно значение из конфигурации с указанным ключом и преобразует его в указанный тип:

public class TestNumModel : PageModel
{
    private readonly IConfiguration Configuration;

    public TestNumModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var number = Configuration.GetValue<int>("NumberKey", 99);
        return Content($"{number}");
    }
}

В приведенном выше коде, если NumberKey отсутствует в конфигурации, используется значение по умолчанию 99.

GetSection, GetChildren и Exists

В следующих примерах рассмотрим файл MySubsection.json.

{
  "section0": {
    "key0": "value00",
    "key1": "value01"
  },
  "section1": {
    "key0": "value10",
    "key1": "value11"
  },
  "section2": {
    "subsection0": {
      "key0": "value200",
      "key1": "value201"
    },
    "subsection1": {
      "key0": "value210",
      "key1": "value211"
    }
  }
}

Следующий код добавляет MySubsection.json к поставщикам конфигурации:

var builder = WebApplication.CreateBuilder(args);

builder.Configuration
    .AddJsonFile("MySubsection.json",
                 optional: true,
                 reloadOnChange: true);

builder.Services.AddRazorPages();

var app = builder.Build();

GetSection

IConfiguration.GetSection возвращает подраздел конфигурации с указанным ключом подраздела.

Следующий код возвращает значения для section1:

public class TestSectionModel : PageModel
{
    private readonly IConfiguration Config;

    public TestSectionModel(IConfiguration configuration)
    {
        Config = configuration.GetSection("section1");
    }

    public ContentResult OnGet()
    {
        return Content(
                $"section1:key0: '{Config["key0"]}'\n" +
                $"section1:key1: '{Config["key1"]}'");
    }
}

Следующий код возвращает значения для section2:subsection0:

public class TestSection2Model : PageModel
{
    private readonly IConfiguration Config;

    public TestSection2Model(IConfiguration configuration)
    {
        Config = configuration.GetSection("section2:subsection0");
    }

    public ContentResult OnGet()
    {
        return Content(
                $"section2:subsection0:key0 '{Config["key0"]}'\n" +
                $"section2:subsection0:key1:'{Config["key1"]}'");
    }
}

Значение GetSection никогда не возвращает значение null. Если соответствующий раздел не найден, возвращается пустой параметр IConfigurationSection.

Когда GetSection возвращает соответствующий раздел, Value не заполняется. Key и Path возвращаются, если раздел существует.

GetChildren и Exists

Следующий код вызывает IConfiguration.GetChildren и возвращает значения для section2:subsection0:

public class TestSection4Model : PageModel
{
    private readonly IConfiguration Config;

    public TestSection4Model(IConfiguration configuration)
    {
        Config = configuration;
    }

    public ContentResult OnGet()
    {
        string s = "";
        var selection = Config.GetSection("section2");
        if (!selection.Exists())
        {
            throw new Exception("section2 does not exist.");
        }
        var children = selection.GetChildren();

        foreach (var subSection in children)
        {
            int i = 0;
            var key1 = subSection.Key + ":key" + i++.ToString();
            var key2 = subSection.Key + ":key" + i.ToString();
            s += key1 + " value: " + selection[key1] + "\n";
            s += key2 + " value: " + selection[key2] + "\n";
        }
        return Content(s);
    }
}

Приведенный выше код вызывает ConfigurationExtensions.Exists для проверки существования раздела:

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

ConfigurationBinder.Bind поддерживает массивы привязки к объектам с помощью массива индексов в ключах конфигурации. Любой формат массива, который предоставляет сегмент числового ключа способен привязать массив к массиву класса POCO.

Рассмотрим MyArray.json из примера загрузки:

{
  "array": {
    "entries": {
      "0": "value00",
      "1": "value10",
      "2": "value20",
      "4": "value40",
      "5": "value50"
    }
  }
}

Следующий код добавляет MyArray.json к поставщикам конфигурации:

var builder = WebApplication.CreateBuilder(args);

builder.Configuration
    .AddJsonFile("MyArray.json",
                 optional: true,
                 reloadOnChange: true);

builder.Services.AddRazorPages();

var app = builder.Build();

Следующий код считывает конфигурацию и отображает значения:

public class ArrayModel : PageModel
{
    private readonly IConfiguration Config;
    public ArrayExample? _array { get; private set; }

    public ArrayModel(IConfiguration config)
    {
        Config = config;
    }

    public ContentResult OnGet()
    {
       _array = Config.GetSection("array").Get<ArrayExample>();
        if (_array == null)
        {
            throw new ArgumentNullException(nameof(_array));
        }
        string s = String.Empty;

        for (int j = 0; j < _array.Entries.Length; j++)
        {
            s += $"Index: {j}  Value:  {_array.Entries[j]} \n";
        }

        return Content(s);
    }
}
public class ArrayExample
{
    public string[]? Entries { get; set; } 
}

Предыдущий код возвращает следующие выходные данные:

Index: 0  Value: value00
Index: 1  Value: value10
Index: 2  Value: value20
Index: 3  Value: value40
Index: 4  Value: value50

В предыдущих выходных данных индекс 3 имеет значение value40, соответствующее "4": "value40", в файле MyArray.json. Индексы привязанного массива непрерывны и не привязаны к индексу ключа конфигурации. Модуль привязки конфигурации не поддерживает привязку значений NULL или создание записей NULL в связанных объектах.

Поставщик пользовательской конфигурации

Пример приложения демонстрирует, как создать базовый поставщик конфигурации, который считывает пары "ключ — значение" конфигурации из базы данных, используя Entity Framework (EF).

Поставщик имеет следующие характеристики.

  • База данных в памяти EF используется для демонстрационных целей. Чтобы использовать базу данных, для которой требуется строка подключения, выполните вторичный ConfigurationBuilder, чтобы предоставить строку подключения от другого поставщика конфигурации.
  • Поставщик считывает таблицу базы данных в конфигурации при запуске. Поставщик не запрашивает базу данных для каждого ключа.
  • Функция перезагрузки на изменение не реализована, поэтому обновление базы данных после запуска приложения не влияет на конфигурацию приложения.

Определите сущность EFConfigurationValue для хранения значений конфигурации в базе данных.

Models/EFConfigurationValue.cs:

public class EFConfigurationValue
{
    public string Id { get; set; } = String.Empty;
    public string Value { get; set; } = String.Empty;
}

Добавьте EFConfigurationContext в хранилище и обратитесь к настроенным значениям.

EFConfigurationProvider/EFConfigurationContext.cs:

public class EFConfigurationContext : DbContext
{
    public EFConfigurationContext(DbContextOptions<EFConfigurationContext> options) : base(options)
    {
    }

    public DbSet<EFConfigurationValue> Values => Set<EFConfigurationValue>();
}

Создайте класс, реализующий IConfigurationSource.

EFConfigurationProvider/EFConfigurationSource.cs:

public class EFConfigurationSource : IConfigurationSource
{
    private readonly Action<DbContextOptionsBuilder> _optionsAction;

    public EFConfigurationSource(Action<DbContextOptionsBuilder> optionsAction) => _optionsAction = optionsAction;

    public IConfigurationProvider Build(IConfigurationBuilder builder) => new EFConfigurationProvider(_optionsAction);
}

Создайте пользовательский поставщик конфигурации путем наследования от ConfigurationProvider. Поставщик конфигурации инициализирует пустую базу данных. Так как конфигурационные ключи не учитывают регистр, словарь, используемый для инициализации базы данных, создается с помощью функции сравнения без учета регистра (StringComparer.OrdinalIgnoreCase).

EFConfigurationProvider/EFConfigurationProvider.cs:

public class EFConfigurationProvider : ConfigurationProvider
{
    public EFConfigurationProvider(Action<DbContextOptionsBuilder> optionsAction)
    {
        OptionsAction = optionsAction;
    }

    Action<DbContextOptionsBuilder> OptionsAction { get; }

    public override void Load()
    {
        var builder = new DbContextOptionsBuilder<EFConfigurationContext>();

        OptionsAction(builder);

        using (var dbContext = new EFConfigurationContext(builder.Options))
        {
            if (dbContext == null || dbContext.Values == null)
            {
                throw new Exception("Null DB context");
            }
            dbContext.Database.EnsureCreated();

            Data = !dbContext.Values.Any()
                ? CreateAndSaveDefaultValues(dbContext)
                : dbContext.Values.ToDictionary(c => c.Id, c => c.Value);
        }
    }

    private static IDictionary<string, string> CreateAndSaveDefaultValues(
        EFConfigurationContext dbContext)
    {
        // Quotes (c)2005 Universal Pictures: Serenity
        // https://www.uphe.com/movies/serenity-2005
        var configValues =
            new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
            {
                    { "quote1", "I aim to misbehave." },
                    { "quote2", "I swallowed a bug." },
                    { "quote3", "You can't stop the signal, Mal." }
            };

        if (dbContext == null || dbContext.Values == null)
        {
            throw new Exception("Null DB context");
        }

        dbContext.Values.AddRange(configValues
            .Select(kvp => new EFConfigurationValue
            {
                Id = kvp.Key,
                Value = kvp.Value
            })
            .ToArray());

        dbContext.SaveChanges();

        return configValues;
    }
}

Метод расширения AddEFConfiguration позволяет добавить источник конфигурации к ConfigurationBuilder.

Extensions/EntityFrameworkExtensions.cs:

public static class EntityFrameworkExtensions
{
    public static IConfigurationBuilder AddEFConfiguration(
               this IConfigurationBuilder builder,
               Action<DbContextOptionsBuilder> optionsAction)
    {
        return builder.Add(new EFConfigurationSource(optionsAction));
    }
}

В следующем коде показано, как использовать пользовательский EFConfigurationProvider в Program.cs.

//using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddEFConfiguration(
    opt => opt.UseInMemoryDatabase("InMemoryDb"));

var app = builder.Build();

app.Run();

Конфигурация доступа с внедрением зависимостей (DI)

Конфигурацию можно внедрить в службы с помощью внедрения зависимостей (DI) путем разрешения службы IConfiguration:

public class Service
{
    private readonly IConfiguration _config;

    public Service(IConfiguration config) =>
        _config = config;

    public void DoSomething()
    {
        var configSettingValue = _config["ConfigSetting"];

        // ...
    }
}

Сведения о том, как получить доступ к значениям с помощью IConfiguration, см. в разделах GetValue и GetSection, GetChildren и Exists данной статьи.

Конфигурация доступа в RazorPages

В следующем коде отображаются данные конфигурации в RazorPage:

@page
@model Test5Model
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

Configuration value for 'MyKey': @Configuration["MyKey"]

В следующем коде MyOptions добавляется в контейнер службы с помощью интерфейса Configure и привязывается к конфигурации:

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<MyOptions>(
    builder.Configuration.GetSection("MyOptions"));

var app = builder.Build();

В следующей разметке для разрешения и вывода значений параметров используется директива @injectRazor.

@page
@model SampleApp.Pages.Test3Model
@using Microsoft.Extensions.Options
@using SampleApp.Models
@inject IOptions<MyOptions> optionsAccessor


<p><b>Option1:</b> @optionsAccessor.Value.Option1</p>
<p><b>Option2:</b> @optionsAccessor.Value.Option2</p>

Доступ к конфигурации в файле представления MVC

В следующем коде отображаются данные конфигурации в представлении MVC:

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

Configuration value for 'MyKey': @Configuration["MyKey"]

Доступ к конфигурации в Program.cs

Следующий код получает доступ к конфигурации в файле Program.cs.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

var key1 = app.Configuration.GetValue<int>("KeyOne");
var key2 = app.Configuration.GetValue<bool>("KeyTwo");

app.Logger.LogInformation($"KeyOne = {key1}");
app.Logger.LogInformation($"KeyTwo = {key2}");

app.Run();

Настройка параметров с помощью делегата

Параметры, настроенные в делегате, переопределяют значения, заданные в поставщиках конфигурации.

В приведенном ниже коде в контейнер службы добавляется служба IConfigureOptions<TOptions>. Она использует делегат для настройки значений для MyOptions:

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<MyOptions>(myOptions =>
{
    myOptions.Option1 = "Value configured in delegate";
    myOptions.Option2 = 500;
});

var app = builder.Build();

Следующий код отображает значения параметров:

public class Test2Model : PageModel
{
    private readonly IOptions<MyOptions> _optionsDelegate;

    public Test2Model(IOptions<MyOptions> optionsDelegate )
    {
        _optionsDelegate = optionsDelegate;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_optionsDelegate.Value.Option1} \n" +
                       $"Option2: {_optionsDelegate.Value.Option2}");
    }
}

В предыдущем примере значения Option1 и Option2 задаются в файле appsettings.json , а затем переопределяются настроенным делегатом.

Конфигурация узла и приложения

Перед настройкой и запуском приложения настройте и запустите узел. Узел отвечает за запуск приложения и управление временем существования. Как приложение, так и узел настраиваются с использованием поставщиков конфигурации, описанных в этом разделе. Пары "ключ — значение" конфигурации узлов также включаются в конфигурацию приложения. Дополнительные сведения о том, как используются поставщики конфигурации при создании узла и как источники конфигурации влияют на его настройку, см. в статье Основы ASP.NET Core.

Конфигурация узла по умолчанию

Подробные сведения о конфигурации по умолчанию при использовании веб-узла см. в разделе о версии ASP.NET Core 2.2 в этой статье.

  • Существуют следующие способы предоставления конфигурации узла.
  • Устанавливается конфигурация веб-узла по умолчанию (ConfigureWebHostDefaults):
    • Kestrel используется в качестве веб-сервера и настраивается посредством поставщиков конфигурации приложения.
    • Добавьте ПО промежуточного слоя фильтрации узлов.
    • Если переменной среды ASPNETCORE_FORWARDEDHEADERS_ENABLED присвоено значение true, добавьте ПО промежуточного слоя перенаправления заголовков.
    • Включите интеграцию служб IIS.

Другая конфигурация

Этот раздел относится только к конфигурации приложений. Другие аспекты запуска и размещения приложений ASP.NET Core настраиваются с помощью файлов конфигурации, которые не рассматриваются в этом разделе.

Переменные среды, заданные в launchSettings.json, переопределяют переменные, заданные в системной среде.

Дополнительные сведения о переносе конфигурации приложений из более ранних версий ASP.NET см. в статье Обновление с ASP.NET до ASP.NET Core.

Добавление конфигурации из внешней сборки

Реализация IHostingStartup позволяет при запуске добавлять в приложение улучшения из внешней сборки вне приложения класса Startup. Дополнительные сведения см. в статье Использование начальных сборок размещения в ASP.NET Core.

Дополнительные ресурсы

Конфигурация конечной точки Kestrel

Конфигурация конкретной конечной точки Kestrel переопределяет все межсерверные конфигурации конечной точки. Конфигурации межсерверных конечных точек включают:

Обратите внимание на следующий файл appsettings.json , используемый в веб-приложении ASP.NET Core:

{
  "Kestrel": {
    "Endpoints": {
      "Https": {
        "Url": "https://localhost:9999"
      }
    }
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
} 

Если предыдущая выделенная разметка используется в веб-приложении ASP.NET Core и приложение запускается в командной строке со следующей конфигурацией межсерверной конечной точки:

dotnet run --urls="https://localhost:7777"

Kestrel привязывается к конечной точке, настроенной специально для Kestrel в файле appsettings.json (https://localhost:9999), а не https://localhost:7777.

Рассмотрим конкретную конечную точку Kestrel, настроенную в качестве переменной среды:

set Kestrel__Endpoints__Https__Url=https://localhost:8888

В предыдущей переменной среды Https является именем конкретной конечной точки Kestrel. Предыдущий файл appsettings.json также определяет Kestrel конкретную конечную точку с именем Https. По умолчанию переменные среды, использующие поставщик конфигурации переменных среды считываются после appsettings.{Environment}.json. Поэтому для конечной точки Https используется предыдущая переменная среды.

GetValue

ConfigurationBinder.GetValue извлекает одно значение из конфигурации с указанным ключом и преобразует его в указанный тип: Этот метод является методом расширения для IConfiguration:

public class TestNumModel : PageModel
{
    private readonly IConfiguration Configuration;

    public TestNumModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var number = Configuration.GetValue<int>("NumberKey", 99);
        return Content($"{number}");
    }
}

В приведенном выше коде, если NumberKey отсутствует в конфигурации, используется значение по умолчанию 99.

GetSection, GetChildren и Exists

В следующих примерах рассмотрим файл MySubsection.json.

{
  "section0": {
    "key0": "value00",
    "key1": "value01"
  },
  "section1": {
    "key0": "value10",
    "key1": "value11"
  },
  "section2": {
    "subsection0": {
      "key0": "value200",
      "key1": "value201"
    },
    "subsection1": {
      "key0": "value210",
      "key1": "value211"
    }
  }
}

Следующий код добавляет MySubsection.json к поставщикам конфигурации:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddJsonFile("MySubsection.json", 
                    optional: true, 
                    reloadOnChange: true);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

GetSection

IConfiguration.GetSection возвращает подраздел конфигурации с указанным ключом подраздела.

Следующий код возвращает значения для section1:

public class TestSectionModel : PageModel
{
    private readonly IConfiguration Config;

    public TestSectionModel(IConfiguration configuration)
    {
        Config = configuration.GetSection("section1");
    }

    public ContentResult OnGet()
    {
        return Content(
                $"section1:key0: '{Config["key0"]}'\n" +
                $"section1:key1: '{Config["key1"]}'");
    }
}

Следующий код возвращает значения для section2:subsection0:

public class TestSection2Model : PageModel
{
    private readonly IConfiguration Config;

    public TestSection2Model(IConfiguration configuration)
    {
        Config = configuration.GetSection("section2:subsection0");
    }

    public ContentResult OnGet()
    {
        return Content(
                $"section2:subsection0:key0 '{Config["key0"]}'\n" +
                $"section2:subsection0:key1:'{Config["key1"]}'");
    }
}

Значение GetSection никогда не возвращает значение null. Если соответствующий раздел не найден, возвращается пустой параметр IConfigurationSection.

Когда GetSection возвращает соответствующий раздел, Value не заполняется. Key и Path возвращаются, если раздел существует.

GetChildren и Exists

Следующий код вызывает IConfiguration.GetChildren и возвращает значения для section2:subsection0:

public class TestSection4Model : PageModel
{
    private readonly IConfiguration Config;

    public TestSection4Model(IConfiguration configuration)
    {
        Config = configuration;
    }

    public ContentResult OnGet()
    {
        string s = null;
        var selection = Config.GetSection("section2");
        if (!selection.Exists())
        {
            throw new System.Exception("section2 does not exist.");
        }
        var children = selection.GetChildren();

        foreach (var subSection in children)
        {
            int i = 0;
            var key1 = subSection.Key + ":key" + i++.ToString();
            var key2 = subSection.Key + ":key" + i.ToString();
            s += key1 + " value: " + selection[key1] + "\n";
            s += key2 + " value: " + selection[key2] + "\n";
        }
        return Content(s);
    }
}

Приведенный выше код вызывает ConfigurationExtensions.Exists для проверки существования раздела:

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

ConfigurationBinder.Bind поддерживает массивы привязки к объектам с помощью массива индексов в ключах конфигурации. Любой формат массива, который предоставляет сегмент числового ключа способен привязать массив к массиву класса POCO.

Рассмотрим MyArray.json из примера загрузки:

{
  "array": {
    "entries": {
      "0": "value00",
      "1": "value10",
      "2": "value20",
      "4": "value40",
      "5": "value50"
    }
  }
}

Следующий код добавляет MyArray.json к поставщикам конфигурации:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddJsonFile("MyArray.json", 
                    optional: true, 
                    reloadOnChange: true);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

Следующий код считывает конфигурацию и отображает значения:

public class ArrayModel : PageModel
{
    private readonly IConfiguration Config;
    public ArrayExample _array { get; private set; }

    public ArrayModel(IConfiguration config)
    {
        Config = config;
    }

    public ContentResult OnGet()
    {
        _array = Config.GetSection("array").Get<ArrayExample>();
        string s = null;

        for (int j = 0; j < _array.Entries.Length; j++)
        {
            s += $"Index: {j}  Value:  {_array.Entries[j]} \n";
        }

        return Content(s);
    }
}

Предыдущий код возвращает следующие выходные данные:

Index: 0  Value: value00
Index: 1  Value: value10
Index: 2  Value: value20
Index: 3  Value: value40
Index: 4  Value: value50

В предыдущих выходных данных индекс 3 имеет значение value40, соответствующее "4": "value40", в файле MyArray.json. Индексы привязанного массива непрерывны и не привязаны к индексу ключа конфигурации. Модуль привязки конфигурации не поддерживает привязку значений NULL или создание записей NULL в связанных объектах

Следующий код загружает конфигурацию array:entries с помощью метода расширения AddInMemoryCollection:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args)
    {
        var arrayDict = new Dictionary<string, string>
        {
            {"array:entries:0", "value0"},
            {"array:entries:1", "value1"},
            {"array:entries:2", "value2"},
            //              3   Skipped
            {"array:entries:4", "value4"},
            {"array:entries:5", "value5"}
        };

        return Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddInMemoryCollection(arrayDict);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
    }
}

Следующий код считывает конфигурацию в arrayDictDictionary и отображает значения:

public class ArrayModel : PageModel
{
    private readonly IConfiguration Config;
    public ArrayExample _array { get; private set; }

    public ArrayModel(IConfiguration config)
    {
        Config = config;
    }

    public ContentResult OnGet()
    {
        _array = Config.GetSection("array").Get<ArrayExample>();
        string s = null;

        for (int j = 0; j < _array.Entries.Length; j++)
        {
            s += $"Index: {j}  Value:  {_array.Entries[j]} \n";
        }

        return Content(s);
    }
}

Предыдущий код возвращает следующие выходные данные:

Index: 0  Value: value0
Index: 1  Value: value1
Index: 2  Value: value2
Index: 3  Value: value4
Index: 4  Value: value5

Индекс #3 в связанном объекте содержит данные конфигурации для конфигурационного ключа array:4 и его значения value4. При привязке данных конфигурации, содержащих массив индексов, в ключах конфигурации эти индексы используются для выполнения итерации данных конфигурации при создании объекта. Когда массив ключей конфигурации пропускает один или несколько индексов, в данных конфигурации не может быть сохранено нулевое значение и в связанном объекте не создается нулевая запись.

Отсутствующий элемент конфигурации для индекса #3 может быть предоставлен перед привязкой к экземпляру ArrayExample любым поставщиком конфигурации, который считывает пару "ключ-значение" индекса #3. Рассмотрим следующий файл Value3.json из примера загрузки:

{
  "array:entries:3": "value3"
}

Следующий код включает конфигурацию для Value3.json и arrayDictDictionary:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args)
    {
        var arrayDict = new Dictionary<string, string>
        {
            {"array:entries:0", "value0"},
            {"array:entries:1", "value1"},
            {"array:entries:2", "value2"},
            //              3   Skipped
            {"array:entries:4", "value4"},
            {"array:entries:5", "value5"}
        };

        return Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddInMemoryCollection(arrayDict);
                config.AddJsonFile("Value3.json",
                                    optional: false, reloadOnChange: false);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
    }
}

Следующий код считывает предыдущую конфигурацию и отображает значения:

public class ArrayModel : PageModel
{
    private readonly IConfiguration Config;
    public ArrayExample _array { get; private set; }

    public ArrayModel(IConfiguration config)
    {
        Config = config;
    }

    public ContentResult OnGet()
    {
        _array = Config.GetSection("array").Get<ArrayExample>();
        string s = null;

        for (int j = 0; j < _array.Entries.Length; j++)
        {
            s += $"Index: {j}  Value:  {_array.Entries[j]} \n";
        }

        return Content(s);
    }
}

Предыдущий код возвращает следующие выходные данные:

Index: 0  Value: value0
Index: 1  Value: value1
Index: 2  Value: value2
Index: 3  Value: value3
Index: 4  Value: value4
Index: 5  Value: value5

Пользовательские поставщики конфигурации не обязаны реализовывать привязку массива.

Поставщик пользовательской конфигурации

Пример приложения демонстрирует, как создать базовый поставщик конфигурации, который считывает пары "ключ — значение" конфигурации из базы данных, используя Entity Framework (EF).

Поставщик имеет следующие характеристики.

  • База данных в памяти EF используется для демонстрационных целей. Чтобы использовать базу данных, для которой требуется строка подключения, выполните вторичный ConfigurationBuilder, чтобы предоставить строку подключения от другого поставщика конфигурации.
  • Поставщик считывает таблицу базы данных в конфигурации при запуске. Поставщик не запрашивает базу данных для каждого ключа.
  • Функция перезагрузки на изменение не реализована, поэтому обновление базы данных после запуска приложения не влияет на конфигурацию приложения.

Определите сущность EFConfigurationValue для хранения значений конфигурации в базе данных.

Models/EFConfigurationValue.cs:

public class EFConfigurationValue
{
    public string Id { get; set; }
    public string Value { get; set; }
}

Добавьте EFConfigurationContext в хранилище и обратитесь к настроенным значениям.

EFConfigurationProvider/EFConfigurationContext.cs:

// using Microsoft.EntityFrameworkCore;

public class EFConfigurationContext : DbContext
{
    public EFConfigurationContext(DbContextOptions options) : base(options)
    {
    }

    public DbSet<EFConfigurationValue> Values { get; set; }
}

Создайте класс, реализующий IConfigurationSource.

EFConfigurationProvider/EFConfigurationSource.cs:

// using Microsoft.EntityFrameworkCore;
// using Microsoft.Extensions.Configuration;

public class EFConfigurationSource : IConfigurationSource
{
    private readonly Action<DbContextOptionsBuilder> _optionsAction;

    public EFConfigurationSource(Action<DbContextOptionsBuilder> optionsAction)
    {
        _optionsAction = optionsAction;
    }

    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new EFConfigurationProvider(_optionsAction);
    }
}

Создайте пользовательский поставщик конфигурации путем наследования от ConfigurationProvider. Поставщик конфигурации инициализирует пустую базу данных. Так как конфигурационные ключи не учитывают регистр, словарь, используемый для инициализации базы данных, создается с помощью функции сравнения без учета регистра (StringComparer.OrdinalIgnoreCase).

EFConfigurationProvider/EFConfigurationProvider.cs:

// using Microsoft.EntityFrameworkCore;
// using Microsoft.Extensions.Configuration;

public class EFConfigurationProvider : ConfigurationProvider
{
    public EFConfigurationProvider(Action<DbContextOptionsBuilder> optionsAction)
    {
        OptionsAction = optionsAction;
    }

    Action<DbContextOptionsBuilder> OptionsAction { get; }

    public override void Load()
    {
        var builder = new DbContextOptionsBuilder<EFConfigurationContext>();

        OptionsAction(builder);

        using (var dbContext = new EFConfigurationContext(builder.Options))
        {
            dbContext.Database.EnsureCreated();

            Data = !dbContext.Values.Any()
                ? CreateAndSaveDefaultValues(dbContext)
                : dbContext.Values.ToDictionary(c => c.Id, c => c.Value);
        }
    }

    private static IDictionary<string, string> CreateAndSaveDefaultValues(
        EFConfigurationContext dbContext)
    {
        // Quotes (c)2005 Universal Pictures: Serenity
        // https://www.uphe.com/movies/serenity-2005
        var configValues = 
            new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
            {
                { "quote1", "I aim to misbehave." },
                { "quote2", "I swallowed a bug." },
                { "quote3", "You can't stop the signal, Mal." }
            };

        dbContext.Values.AddRange(configValues
            .Select(kvp => new EFConfigurationValue 
                {
                    Id = kvp.Key,
                    Value = kvp.Value
                })
            .ToArray());

        dbContext.SaveChanges();

        return configValues;
    }
}

Метод расширения AddEFConfiguration позволяет добавить источник конфигурации к ConfigurationBuilder.

Extensions/EntityFrameworkExtensions.cs:

// using Microsoft.EntityFrameworkCore;
// using Microsoft.Extensions.Configuration;

public static class EntityFrameworkExtensions
{
    public static IConfigurationBuilder AddEFConfiguration(
        this IConfigurationBuilder builder, 
        Action<DbContextOptionsBuilder> optionsAction)
    {
        return builder.Add(new EFConfigurationSource(optionsAction));
    }
}

В следующем коде показано, как использовать пользовательский EFConfigurationProvider в Program.cs.

// using Microsoft.EntityFrameworkCore;

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            config.AddEFConfiguration(
                options => options.UseInMemoryDatabase("InMemoryDb"));
        })

Доступ к конфигурации во время запуска

В следующем коде отображаются данные конфигурации в методах Startup:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
        Console.WriteLine($"MyKey : {Configuration["MyKey"]}");
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        Console.WriteLine($"Position:Title : {Configuration["Position:Title"]}");

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
        });
    }
}

Дополнительные сведения см. в руководстве по доступу к конфигурации с использованием удобных методов.

Конфигурация доступа в RazorPages

В следующем коде отображаются данные конфигурации в RazorPage:

@page
@model Test5Model
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

Configuration value for 'MyKey': @Configuration["MyKey"]

В следующем коде MyOptions добавляется в контейнер службы с помощью интерфейса Configure и привязывается к конфигурации:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));

    services.AddRazorPages();
}

В следующей разметке для разрешения и вывода значений параметров используется директива @injectRazor.

@page
@model SampleApp.Pages.Test3Model
@using Microsoft.Extensions.Options
@inject IOptions<MyOptions> optionsAccessor


<p><b>Option1:</b> @optionsAccessor.Value.Option1</p>
<p><b>Option2:</b> @optionsAccessor.Value.Option2</p>

Доступ к конфигурации в файле представления MVC

В следующем коде отображаются данные конфигурации в представлении MVC:

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

Configuration value for 'MyKey': @Configuration["MyKey"]

Настройка параметров с помощью делегата

Параметры, настроенные в делегате, переопределяют значения, заданные в поставщиках конфигурации.

Настройка параметров с помощью делегата демонстрируется в примере 2 в примере приложения.

В приведенном ниже коде в контейнер службы добавляется служба IConfigureOptions<TOptions>. Она использует делегат для настройки значений для MyOptions:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyOptions>(myOptions =>
    {
        myOptions.Option1 = "Value configured in delegate";
        myOptions.Option2 = 500;
    });

    services.AddRazorPages();
}

Следующий код отображает значения параметров:

public class Test2Model : PageModel
{
    private readonly IOptions<MyOptions> _optionsDelegate;

    public Test2Model(IOptions<MyOptions> optionsDelegate )
    {
        _optionsDelegate = optionsDelegate;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_optionsDelegate.Value.Option1} \n" +
                       $"Option2: {_optionsDelegate.Value.Option2}");
    }
}

В предыдущем примере значения Option1 и Option2 задаются в файле appsettings.json , а затем переопределяются настроенным делегатом.

Конфигурация узла и приложения

Перед настройкой и запуском приложения настройте и запустите узел. Узел отвечает за запуск приложения и управление временем существования. Как приложение, так и узел настраиваются с использованием поставщиков конфигурации, описанных в этом разделе. Пары "ключ — значение" конфигурации узлов также включаются в конфигурацию приложения. Дополнительные сведения о том, как используются поставщики конфигурации при создании узла и как источники конфигурации влияют на его настройку, см. в статье Основы ASP.NET Core.

Конфигурация узла по умолчанию

Подробные сведения о конфигурации по умолчанию при использовании веб-узла см. в разделе о версии ASP.NET Core 2.2 в этой статье.

  • Существуют следующие способы предоставления конфигурации узла.
    • Переменные среды с префиксом DOTNET_ (например, DOTNET_ENVIRONMENT), использующие поставщик конфигурации переменных среды. Префикс (DOTNET_) исключается при загрузке пар "ключ — значение" конфигурации.
    • Аргументы командной строки, использующие поставщик конфигурации командной строки.
  • Устанавливается конфигурация веб-узла по умолчанию (ConfigureWebHostDefaults):
    • Kestrel используется в качестве веб-сервера и настраивается посредством поставщиков конфигурации приложения.
    • Добавьте ПО промежуточного слоя фильтрации узлов.
    • Если переменной среды ASPNETCORE_FORWARDEDHEADERS_ENABLED присвоено значение true, добавьте ПО промежуточного слоя перенаправления заголовков.
    • Включите интеграцию служб IIS.

Другая конфигурация

Этот раздел относится только к конфигурации приложений. Другие аспекты запуска и размещения приложений ASP.NET Core настраиваются с помощью файлов конфигурации, которые не рассматриваются в этом разделе.

Переменные среды, заданные в launchSettings.json, переопределяют переменные, заданные в системной среде.

Дополнительные сведения о переносе конфигурации приложений из более ранних версий ASP.NET см. в статье Обновление с ASP.NET до ASP.NET Core.

Добавление конфигурации из внешней сборки

Реализация IHostingStartup позволяет при запуске добавлять в приложение улучшения из внешней сборки вне приложения класса Startup. Дополнительные сведения см. в статье Использование начальных сборок размещения в ASP.NET Core.

Дополнительные ресурсы