ASP.NET Core 中的配置

作者:Luke Latham

ASP.NET Core 中的应用配置基于配置提供程序 建立的键值对。 配置提供程序将配置数据从各种配置源读取到键值对:

  • Azure Key Vault
  • Azure 应用程序配置
  • 命令行参数
  • (已安装或已创建的)自定义提供程序
  • 目录文件
  • 环境变量
  • 内存中的 .NET 对象
  • 设置文件

框架隐式包含通用配置提供程序方案的配置包 (Microsoft Extensions.Configuration)。

后面的代码示例和示例应用中的代码示例使用 Microsoft.Extensions.Configuration 命名空间:

using Microsoft.Extensions.Configuration;

选项模式 是本主题中描述的配置概念的扩展。 选项使用类来表示相关设置的组。 有关详细信息,请参阅 ASP.NET Core 中的选项模式

查看或下载示例代码如何下载

主机与应用配置

在配置并启动应用之前,配置并启动主机 。 主机负责应用程序启动和生存期管理。 应用和主机均使用本主题中所述的配置提供程序进行配置。 应用的配置中也包含主机配置键值对。 有关在构建主机时如何使用配置提供程序以及配置源如何影响主机配置的详细信息,请参阅 ASP.NET Core 基础知识

其他配置

本主题仅与应用配置相关 。 运行和托管 ASP.NET Core 应用的其他方面是使用本主题中未包含的配置文件进行配置:

若要详细了解如何从旧版 ASP.NET 迁移应用配置,请参阅 从 ASP.NET 迁移到 ASP.NET Core

默认配置

基于 ASP.NET Core dotnet new模板的 Web 应用在生成主机时会调用 CreateDefaultBuilder CreateDefaultBuilder 按照以下顺序为应用提供默认配置:

以下内容适用于使用通用主机的应用。 有关使用 Web 主机时默认配置的详细信息,请参阅本主题的 ASP.NET Core 2.2 版本

  • 主机配置通过以下方式提供:
  • 已建立 Web 主机默认配置 (ConfigureWebHostDefaults):
    • Kestrel 用作 Web 服务器,并使用应用的配置提供程序对其进行配置。
    • 添加主机筛选中间件。
    • 如果 ASPNETCORE_FORWARDEDHEADERS_ENABLED 环境变量设置为 true,则添加转发的标头中间件。
    • 启用 IIS 集成。
  • 应用配置通过以下方式提供:

安全性

采用以下做法来保护敏感配置数据:

  • 请勿在配置提供程序代码或纯文本配置文件中存储密码或其他敏感数据。
  • 不要在开发或测试环境中使用生产机密。
  • 请在项目外部指定机密,避免将其意外提交到源代码存储库。

有关详细信息,请参阅下列主题:

Azure Key Vault 安全存储 ASP.NET Core 应用的应用机密。 有关详细信息,请参阅 ASP.NET Core 中的 Azure Key Vault 配置提供程序

分层配置数据

配置 API 能够通过在配置键中使用分隔符来展平分层数据以保持分层配置数据。

在以下 JSON 文件中,两个节的结构化层次结构中存在四个键:

{
  "section0": {
    "key0": "value",
    "key1": "value"
  },
  "section1": {
    "key0": "value",
    "key1": "value"
  }
}

将文件读入配置时,将创建唯一键以保持配置源的原始分层数据结构。 使用冒号 (:) 展平节和键以保持原始结构:

  • section0:key0
  • section0:key1
  • section1:key0
  • section1:key1

GetSectionGetChildren 方法可用于隔离各个节和配置数据中某节的子节。 稍后将在 GetSection、GetChildren 和 Exists 中介绍这些方法。

约定

源和提供程序

在应用启动时,将按照指定的配置提供程序的顺序读取配置源。

实现更改检测的配置提供程序能够在基础设置更改时重新加载配置。 例如,文件配置提供程序(本主题后面将对此进行介绍)和 Azure Key Vault 配置提供程序实现更改检测。

应用的依赖关系注入 (DI) 容器中提供了 IConfiguration IConfiguration 可注入到 Razor Pages PageModel 或 MVC Controller 来获取以下类的配置。

在下面的示例中,使用 _config 字段来访问配置值:

public class IndexModel : PageModel
{
    private readonly IConfiguration _config;

    public IndexModel(IConfiguration config)
    {
        _config = config;
    }
}
public class HomeController : Controller
{
    private readonly IConfiguration _config;

    public HomeController(IConfiguration config)
    {
        _config = config;
    }
}

配置提供程序不能使用 DI,因为主机在设置这些提供程序时 DI 不可用。

配置键采用以下约定:

  • 键不区分大小写。 例如,ConnectionStringconnectionstring 被视为等效键。
  • 如果由相同或不同的配置提供程序设置相同键的值,则键上设置的最后一个值就是所使用的值。
  • 分层键
    • 在配置 API 中,冒号分隔符 (:) 适用于所有平台。
    • 在环境变量中,冒号分隔符可能无法适用于所有平台。 所有平台均支持采用双下划线 (__),并可以将其自动转换为冒号。
    • 在 Azure Key Vault 中,分层键使用 --(两个破折号)作为分隔符。 将机密加载到应用的配置中时,用冒号替换破折号。
  • ConfigurationBinder 支持使用配置键中的数组索引将数组绑定到对象。 数组绑定将在将数组绑定到类部分中进行介绍。

配置值采用以下约定:

  • 值是字符串。
  • NULL 值不能存储在配置中或绑定到对象。

提供程序

下表显示了 ASP.NET Core 应用可用的配置提供程序。

提供程序 通过以下对象提供配置…
Azure Key Vault 配置提供程序(安全 主题) Azure Key Vault
Azure 应用程序配置提供程序(Azure 文档) Azure 应用程序配置
命令行配置提供程序 命令行参数
自定义配置提供程序 自定义源
环境变量配置提供程序 环境变量
文件配置提供程序 文件(INI、JSON、XML)
Key-per-file 配置提供程序 目录文件
内存配置提供程序 内存中集合
用户机密 (Secret Manager)(安全 主题) 用户配置文件目录中的文件

按照启动时指定的配置提供程序的顺序读取配置源。 本主题中所述的配置提供程序按字母顺序进行介绍,而不是按代码排列顺序进行介绍。 代码中的配置提供程序应以特定顺序排列,从而满足应用所需的基础配置源的优先级。

配置提供程序的典型顺序为:

  1. 文件(appsettings.json、appsettings.{Environment}.json,其中 {Environment} 是应用的当前托管环境)
  2. Azure 密钥保管库
  3. 用户机密 (Secret Manager)(仅限开发环境中)
  4. 环境变量
  5. 命令行参数

通常的做法是将命令行配置提供程序置于一系列提供程序的末尾,以允许命令行参数替代由其他提供程序设置的配置。

使用 CreateDefaultBuilder 初始化新的主机生成器时,将使用上述提供程序序列。 有关详细信息,请参阅默认配置部分。

用 ConfigureHostConfiguration 配置主机生成器

若要配置主机生成器,请调用 ConfigureHostConfiguration 并提供配置。 ConfigureHostConfiguration 初始化 IHostEnvironment,以便稍后在生成过程中使用。 可多次调用 ConfigureHostConfiguration,并得到累计结果。

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureHostConfiguration(config =>
        {
            var dict = new Dictionary<string, string>
            {
                {"MemoryCollectionKey1", "value1"},
                {"MemoryCollectionKey2", "value2"}
            };

            config.AddInMemoryCollection(dict);
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

ConfigureAppConfiguration

构建主机时调用 ConfigureAppConfiguration 以指定应用的配置提供程序以及 CreateDefaultBuilder 自动添加的配置提供程序:

public class Program
{
    public static Dictionary<string, string> arrayDict = 
        new Dictionary<string, string>
        {
            {"array:entries:0", "value0"},
            {"array:entries:1", "value1"},
            {"array:entries:2", "value2"},
            {"array:entries:4", "value4"},
            {"array:entries:5", "value5"}
        };

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

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddInMemoryCollection(arrayDict);
                config.AddJsonFile(
                    "json_array.json", optional: false, reloadOnChange: false);
                config.AddJsonFile(
                    "starship.json", optional: false, reloadOnChange: false);
                config.AddXmlFile(
                    "tvshow.xml", optional: false, reloadOnChange: false);
                config.AddEFConfiguration(
                    options => options.UseInMemoryDatabase("InMemoryDb"));
                config.AddCommandLine(args);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

用命令行参数替代以前的配置

若要提供命令行参数可替代的应用配置,最后请调用 AddCommandLine

.ConfigureAppConfiguration((hostingContext, config) =>
{
    // Call other providers here
    config.AddCommandLine(args);
})

删除 CreateDefaultBuilder 添加的提供程序

要删除 CreateDefaultBuilder 添加的提供程序,请先对 IConfigurationBuilder.Sources 调用 Clear

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.Sources.Clear();
    // Add providers here
})

在应用启动期间使用配置

在应用启动期间,可以使用 ConfigureAppConfiguration 中提供给应用的配置,包括 Startup.ConfigureServices 有关详细信息,请参阅在启动期间访问配置部分。

命令行配置提供程序

CommandLineConfigurationProvider 在运行时从命令行参数键值对加载配置。

要激活命令行配置,请在 ConfigurationBuilder 的实例上调用 AddCommandLine 扩展方法。

调用 CreateDefaultBuilder(string []) 时会自动调用 AddCommandLine 有关详细信息,请参阅默认配置部分。

此外,CreateDefaultBuilder 也会加载:

  • appsettings.json 和 appsettings.{Environment}.json 文件中的可选配置 。
  • 用户机密 (Secret Manager)(在开发环境中)。
  • 环境变量。

CreateDefaultBuilder 最后添加命令行配置提供程序。 在运行时传递的命令行参数会替代由其他提供程序设置的配置。

CreateDefaultBuilder 在构造主机时起作用。 因此,CreateDefaultBuilder 激活的命令行配置可能会影响主机的配置方式。

对于基于 ASP.NET Core 模板的应用,CreateDefaultBuilder 已调用 AddCommandLine 若要添加其他配置提供程序并保持能够用命令行参数替代这些提供程序的配置,请在 ConfigureAppConfiguration 中调用应用的其他提供程序,并最后调用 AddCommandLine

.ConfigureAppConfiguration((hostingContext, config) =>
{
    // Call other providers here
    config.AddCommandLine(args);
})

示例

示例应用利用静态便捷方法 CreateDefaultBuilder 来生成主机,其中包括一个对 AddCommandLine 的调用。

  1. 在项目的目录中打开命令提示符。
  2. dotnet run 命令提供命令行参数 dotnet run CommandLineKey=CommandLineValue
  3. 应用运行后,在 http://localhost:5000 打开应用的浏览器。
  4. 观察输出是否包含提供给 dotnet run 的配置命令行参数的键值对。

自变量

该值必须后跟一个等号 (=),否则当值后跟一个空格时,键必须具有前缀(--/)。 如果使用等号(例如 CommandLineKey=),则不需要该值。

键前缀 示例
无前缀 CommandLineKey1=value1
双划线 (--) --CommandLineKey2=value2--CommandLineKey2 value2
正斜杠 (/) /CommandLineKey3=value3/CommandLineKey3 value3

在同一命令中,不要将使用等号的命令行参数键值对与使用空格的键值对混合使用。

示例命令:

dotnet run CommandLineKey1=value1 --CommandLineKey2=value2 /CommandLineKey3=value3
dotnet run --CommandLineKey1 value1 /CommandLineKey2 value2
dotnet run CommandLineKey1= CommandLineKey2=value2

交换映射

交换映射支持键名替换逻辑。 使用 ConfigurationBuilder 手动构建配置时,需要为 AddCommandLine 方法提供交换替换字典。

当使用交换映射字典时,会检查字典中是否有与命令行参数提供的键匹配的键。 如果在字典中找到命令行键,则传回字典值(键替换)以将键值对设置为应用的配置。 对任何具有单划线 (-) 前缀的命令行键而言,交换映射都是必需的。

交换映射字典键规则:

  • 交换必须以单划线 (-) 或双划线 (--) 开头。
  • 交换映射字典不得包含重复键。

创建交换映射字典。 在以下示例中,创建了两个交换映射:

public static readonly Dictionary<string, string> _switchMappings = 
    new Dictionary<string, string>
    {
        { "-CLKey1", "CommandLineKey1" },
        { "-CLKey2", "CommandLineKey2" }
    };

生成主机后,使用交换映射字典来调用 AddCommandLine

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddCommandLine(args, _switchMappings);
})

对于使用交换映射的应用,调用 CreateDefaultBuilder 不应传递参数。 CreateDefaultBuilder 方法的 AddCommandLine 调用不包括映射的交换,并且无法将交换映射字典传递给 CreateDefaultBuilder 解决方案不是将参数传递给 CreateDefaultBuilder,而是允许 ConfigurationBuilder 方法的 AddCommandLine 方法处理参数和交换映射字典。

创建交换映射字典后,它将包含下表所示的数据。

“值”
-CLKey1 CommandLineKey1
-CLKey2 CommandLineKey2

如果在启动应用时使用了交换映射的键,则配置将接收字典提供的密钥上的配置值:

dotnet run -CLKey1=value1 -CLKey2=value2

运行上述命令后,配置包含下表中显示的值。

“值”
CommandLineKey1 value1
CommandLineKey2 value2

环境变量配置提供程序

EnvironmentVariablesConfigurationProvider 在运行时从环境变量键值对加载配置。

要激活环境变量配置,请在 ConfigurationBuilder 的实例上调用 AddEnvironmentVariables 扩展方法。

在环境变量中使用分层键时,冒号分隔符 (:) 可能无法适用于所有平台(例如 Bash)。 所有平台均支持采用双下划线 (__),并可以用冒号自动替换。

借助 Azure 应用服务,可在 Azure 门户中设置使用环境变量配置提供程序替代应用配置的环境变量。 有关详细信息,请参阅 Azure 应用:使用 Azure 门户替代应用配置

如果使用通用主机初始化新的主机生成器,且调用了 CreateDefaultBuilder,则使用 AddEnvironmentVariables主机配置加载前缀为 DOTNET_ 的环境变量。 有关详细信息,请参阅默认配置部分。

此外,CreateDefaultBuilder 也会加载:

  • 来自没有前缀的环境变量的应用配置,方法是通过调用不带前缀的 AddEnvironmentVariables
  • appsettings.json 和 appsettings.{Environment}.json 文件中的可选配置 。
  • 用户机密 (Secret Manager)(在开发环境中)。
  • 命令行参数。

环境变量配置提供程序是在配置已根据用户机密和 appsettings 文件建立后调用。 在此位置调用提供程序允许在运行时读取的环境变量替代由用户机密和 appsettings 文件设置的配置。

要从其他环境变量提供应用配置,请在 ConfigureAppConfiguration 中调用应用的其他提供程序,并使用前缀调用 AddEnvironmentVariables

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddEnvironmentVariables(prefix: "PREFIX_");
})

最后调用 AddEnvironmentVariables让带给定前缀的环境变量可替代其他提供程序中的值。

示例

示例应用利用静态便捷方法 CreateDefaultBuilder 来生成主机,其中包括一个对 AddEnvironmentVariables 的调用。

  1. 运行示例应用。 http://localhost:5000 打开应用的浏览器。
  2. 观察输出是否包含环境变量 ENVIRONMENT 的键值对。 该值反映了应用运行的环境,在本地运行时通常为 Development

为了缩短应用呈现的环境变量列表,应用会筛选环境变量。 请参阅示例应用的“Pages/Index.cshtml.cs”文件 。

要公开应用可用的所有环境变量,请将 Pages/Index.cshtml.cs 中的 FilteredConfiguration 更改为以下内容 :

FilteredConfiguration = _config.AsEnumerable();

前缀

AddEnvironmentVariables 方法提供前缀时,将筛选加载到应用的配置中的环境变量。 例如,要筛选前缀 CUSTOM_ 上的环境变量,请将前缀提供给配置提供程序:

var config = new ConfigurationBuilder()
    .AddEnvironmentVariables("CUSTOM_")
    .Build();

创建配置键值对时,将去除前缀。

若已创建主机生成器,则主机配置由环境变量提供。 有关用于这些环境变量的前缀的详细信息,请参阅默认配置部分。

连接字符串前缀

针对为应用环境配置 Azure 连接字符串所涉及的四个连接字符串环境变量,配置 API 具有特殊的处理规则。 如果没有向 AddEnvironmentVariables 提供前缀,则具有表中所示前缀的环境变量将加载到应用中。

连接字符串前缀 提供程序
CUSTOMCONNSTR_ 自定义提供程序
MYSQLCONNSTR_ MySQL
SQLAZURECONNSTR_ Azure SQL 数据库
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

示例

在服务器上创建了一个自定义连接字符串环境变量:

  • 名称 – CUSTOMCONNSTR_ReleaseDB
  • 值 – Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True

如果 IConfiguration 已引入并分配给名为 _config 的字段,请读取值:

_config["ConnectionStrings:ReleaseDB"]

文件配置提供程序

FileConfigurationProvider 是从文件系统加载配置的基类。 以下配置提供程序专用于特定文件类型:

INI 配置提供程序

IniConfigurationProvider 在运行时从 INI 文件键值对加载配置。

若要激活 INI 文件配置,请在 ConfigurationBuilder 的实例上调用 AddIniFile 扩展方法。

冒号可用作 INI 文件配置中的节分隔符。

重载允许指定:

  • 文件是否可选。
  • 如果文件更改,是否重载配置。
  • IFileProvider 用于访问该文件。

构建主机时调用 ConfigureAppConfiguration 以指定应用的配置:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddIniFile(
        "config.ini", optional: true, reloadOnChange: true);
})

INI 配置文件的通用示例:

[section0]
key0=value
key1=value

[section1]
subsection:key=value

[section2:subsection0]
key=value

[section2:subsection1]
key=value

以前的配置文件使用 value 加载以下键:

  • section0:key0
  • section0:key1
  • section1:subsection:key
  • section2:subsection0:key
  • section2:subsection1:key

JSON 配置提供程序

JsonConfigurationProvider 在运行时期间从 JSON 文件键值对加载配置。

若要激活 JSON 文件配置,请在 ConfigurationBuilder 的实例上调用 AddJsonFile 扩展方法。

重载允许指定:

  • 文件是否可选。
  • 如果文件更改,是否重载配置。
  • IFileProvider 用于访问该文件。

使用 CreateDefaultBuilder 初始化新的主机生成器时,会自动调用两次 AddJsonFile 调用该方法来从以下文件加载配置:

  • appsettings.json – 首先读取此文件 。 该文件的环境版本可以替代 appsettings.json 文件提供的值。
  • appsettings.{Environment}.json – 根据 IHostingEnvironment.EnvironmentName 加载文件的环境版本 。

有关详细信息,请参阅默认配置部分。

此外,CreateDefaultBuilder 也会加载:

首先建立 JSON 配置提供程序。 因此,用户机密、环境变量和命令行参数会替代由 appsettings 文件设置的配置。

构建主机时调用 ConfigureAppConfiguration 以指定除 appsettings.json 和 appsettings.{Environment}.json 以外的文件的应用配置:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddJsonFile(
        "config.json", optional: true, reloadOnChange: true);
})

示例

示例应用利用静态便捷方法 CreateDefaultBuilder 来生成主机,其中包括两个对 AddJsonFile 的调用:

  • 第一次调用 AddJsonFile 会从 appsettings 加载配置 :

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft": "Warning",
          "Microsoft.Hosting.Lifetime": "Information"
        }
      },
      "AllowedHosts": "*"
    }
    
  • 第二次调用 AddJsonFile 会从 appsettings.{Environment}.json 加载配置 。 对于示例应用中的 appsettings.Development.json,将加载以下文件 :

    {
      "Logging": {
        "LogLevel": {
          "Default": "Debug",
          "System": "Information",
          "Microsoft": "Information"
        }
      }
    }
    
  1. 运行示例应用。 http://localhost:5000 打开应用的浏览器。
  2. 输出包含配置的键值对(由应用的环境而定)。 在开发环境中运行应用时,键 Logging:LogLevel:Default 的日志级别为 Debug
  3. 再次在生产环境中运行示例应用:
    1. 打开 Properties/launchSettings.json 文件 。
    2. ConfigurationSample 配置文件中,将 ASPNETCORE_ENVIRONMENT 环境变量的值更改为 Production
    3. 保存文件,然后在命令外壳中使用 dotnet run 运行应用。
  4. appsettings.Development.json 中的设置不再替代 appsettings.json 中的设置 。 Logging:LogLevel:Default 的日志级别为 Information

XML 配置提供程序

XmlConfigurationProvider 在运行时从 XML 文件键值对加载配置。

若要激活 XML 文件配置,请在 ConfigurationBuilder 的实例上调用 AddXmlFile 扩展方法。

重载允许指定:

  • 文件是否可选。
  • 如果文件更改,是否重载配置。
  • IFileProvider 用于访问该文件。

创建配置键值对时,将忽略配置文件的根节点。 不要在文件中指定文档类型定义 (DTD) 或命名空间。

构建主机时调用 ConfigureAppConfiguration 以指定应用的配置:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddXmlFile(
        "config.xml", optional: true, reloadOnChange: true);
})

XML 配置文件可以为重复节使用不同的元素名称:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <section0>
    <key0>value</key0>
    <key1>value</key1>
  </section0>
  <section1>
    <key0>value</key0>
    <key1>value</key1>
  </section1>
</configuration>

以前的配置文件使用 value 加载以下键:

  • section0:key0
  • section0:key1
  • section1:key0
  • section1:key1

如果使用 name 属性来区分元素,则使用相同元素名称的重复元素可以正常工作:

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

以前的配置文件使用 value 加载以下键:

  • section:section0:key:key0
  • section:section0:key:key1
  • section:section1:key:key0
  • section:section1:key:key1

属性可用于提供值:

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

以前的配置文件使用 value 加载以下键:

  • key:attribute
  • section:key:attribute

Key-per-file 配置提供程序

KeyPerFileConfigurationProvider 使用目录的文件作为配置键值对。 该键是文件名。 该值包含文件的内容。 Key-per-file 配置提供程序用于 Docker 托管方案。

若要激活 Key-per-file 配置,请在 ConfigurationBuilder 的实例上调用 AddKeyPerFile 扩展方法。 文件的 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 使用内存中集合作为配置键值对。

若要激活内存中集合配置,请在 ConfigurationBuilder 的实例上调用 AddInMemoryCollection 扩展方法。

可以使用 IEnumerable<KeyValuePair<String,String>> 初始化配置提供程序。

构建主机时调用 ConfigureAppConfiguration 以指定应用的配置。

在下面的示例中,创建了配置字典:

public static readonly Dictionary<string, string> _dict = 
    new Dictionary<string, string>
    {
        {"MemoryCollectionKey1", "value1"},
        {"MemoryCollectionKey2", "value2"}
    };

通过 AddInMemoryCollection 的调用使用字典,以提供配置:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddInMemoryCollection(_dict);
})

GetValue

ConfigurationBinder.GetValueT<> 从配置中提取一个具有指定键的值,并将其转换为指定的非集合类型。 重载接受默认值。

如下示例中:

  • 使用键 NumberKey 从配置中提取字符串值。 如果在配置键中找不到 NumberKey,则使用默认值 99
  • 键入值作为 int
  • 存储 NumberConfig 属性中的值,以供页面使用。
public class IndexModel : PageModel
{
    public IndexModel(IConfiguration config)
    {
        _config = config;
    }

    public int NumberConfig { get; private set; }

    public void OnGet()
    {
        NumberConfig = _config.GetValue<int>("NumberKey", 99);
    }
}

GetSection、GetChildren 和 Exists

对于下面的示例,请考虑以下 JSON 文件。 在两个节中找到四个键,其中一个包含一对子节:

{
  "section0": {
    "key0": "value",
    "key1": "value"
  },
  "section1": {
    "key0": "value",
    "key1": "value"
  },
  "section2": {
    "subsection0" : {
      "key0": "value",
      "key1": "value"
    },
    "subsection1" : {
      "key0": "value",
      "key1": "value"
    }
  }
}

将文件读入配置时,会创建以下唯一的分层键来保存配置值:

  • section0:key0
  • section0:key1
  • section1:key0
  • section1:key1
  • section2:subsection0:key0
  • section2:subsection0:key1
  • section2:subsection1:key0
  • section2:subsection1:key1

GetSection

IConfiguration.GetSection 使用指定的子节键提取配置子节。

若要返回仅包含 section1 中键值对的 IConfigurationSection,请调用 GetSection 并提供节名称:

var configSection = _config.GetSection("section1");

configSection 不具有值,只有密钥和路径。

同样,若要获取 section2:subsection0 中键的值,请调用 GetSection 并提供节路径:

var configSection = _config.GetSection("section2:subsection0");

GetSection 永远不会返回 null 如果找不到匹配的节,则返回空 IConfigurationSection

GetSection 返回匹配的部分时,Value 未填充。 存在该部分时,返回一个 KeyPath 部分。

GetChildren

section2 上调用 IConfiguration.GetChildren 会获得 IEnumerable<IConfigurationSection>,其中包括:

  • subsection0
  • subsection1
var configSection = _config.GetSection("section2");

var children = configSection.GetChildren();

存在

使用 ConfigurationExtensions.Exists 确定配置节是否存在:

var sectionExists = _config.GetSection("section2:subsection2").Exists();

给定示例数据,sectionExistsfalse,因为配置数据中没有 section2:subsection2 节。

绑定至类

可以使用选项模式 将配置绑定到表示相关设置组的类。 有关详细信息,请参阅 ASP.NET Core 中的选项模式

配置值作为字符串返回,但调用 Bind 可以构造 POCO 对象。 绑定器将值绑定到所提供类型的所有公共读取/写入属性。 不会绑定字段 。

示例应用包含 Starship 模型 (Models/Starship.cs ):

public class Starship
{
    public string Name { get; set; }
    public string Registry { get; set; }
    public string Class { get; set; }
    public decimal Length { get; set; }
    public bool Commissioned { get; set; }
}

当示例应用使用 JSON 配置提供程序加载配置时,starship.json 文件的 starship 节会创建配置:

{
  "starship": {
    "name": "USS Enterprise",
    "registry": "NCC-1701",
    "class": "Constitution",
    "length": 304.8,
    "commissioned": false
  },
  "trademark": "Paramount Pictures Corp. http://www.paramount.com"
}

创建以下配置键值对:

“值”
starship:name USS Enterprise
starship:registry NCC-1701
starship:class Constitution
starship:length 304.8
starship:commissioned False
trademark Paramount Pictures Corp. https://www.paramount.com

示例应用使用 starship 键调用 GetSection starship 键值对是独立的。 在子节传入 Starship 类的实例时调用 Bind 方法。 绑定实例值后,将实例分配给用于呈现的属性:

var starship = new Starship();
_config.GetSection("starship").Bind(starship);
Starship = starship;

绑定至对象图

Bind 能够绑定整个 POCO 对象图。 与绑定简单对象一样,只绑定公共读取/写入属性。

该示例包含 TvShow 模型,其对象图包含 MetadataActors 类 (Models/TvShow.cs ):

public class TvShow
{
    public Metadata Metadata { get; set; }
    public Actors Actors { get; set; }
    public string Legal { get; set; }
}

public class Metadata
{
    public string Series { get; set; }
    public string Title { get; set; }
    public DateTime AirDate { get; set; }
    public int Episodes { get; set; }
}

public class Actors
{
    public string Names { get; set; }
}

示例应用有一个包含配置数据的 tvshow.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <tvshow>
    <metadata>
      <series>Dr. Who</series>
      <title>The Sun Makers</title>
      <airdate>11/26/1977</airdate>
      <episodes>4</episodes>
    </metadata>
    <actors>
      <names>Tom Baker, Louise Jameson, John Leeson</names>
    </actors>
    <legal>(c)1977 BBC https://www.bbc.co.uk/programmes/b006q2x0</legal>
  </tvshow>
</configuration>

使用 Bind 方法将配置绑定到整个 TvShow 对象图。 将绑定实例分配给用于呈现的属性:

var tvShow = new TvShow();
_config.GetSection("tvshow").Bind(tvShow);
TvShow = tvShow;

ConfigurationBinder.Get<T> 绑定并返回指定类型。 Get<T> 比使用 Bind 更方便。 以下代码显示如何将 Get<T> 与前面的示例一起使用,该示例允许将绑定实例直接分配给用于呈现的属性:

TvShow = _config.GetSection("tvshow").Get<TvShow>();

将数组绑定至类

示例应用演示了本部分中介绍的概念。

Bind 支持使用配置键中的数组索引将数组绑定到对象。 公开数字键段(:0::1:、… :{n}:)的任何数组格式都能够与 POCO 类数组进行数组绑定。

备注

绑定是按约定提供的。 不需要自定义配置提供程序实现数组绑定。

内存中数组处理

请考虑下表中所示的配置键和值。

“值”
array:entries:0 value0
array:entries:1 value1
array:entries:2 value2
array:entries:4 value4
array:entries:5 value5

使用内存配置提供程序在示例应用中加载这些键和值:

public class Program
{
    public static Dictionary<string, string> arrayDict = 
        new Dictionary<string, string>
        {
            {"array:entries:0", "value0"},
            {"array:entries:1", "value1"},
            {"array:entries:2", "value2"},
            {"array:entries:4", "value4"},
            {"array:entries:5", "value5"}
        };

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

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddInMemoryCollection(arrayDict);
                config.AddJsonFile(
                    "json_array.json", optional: false, reloadOnChange: false);
                config.AddJsonFile(
                    "starship.json", optional: false, reloadOnChange: false);
                config.AddXmlFile(
                    "tvshow.xml", optional: false, reloadOnChange: false);
                config.AddEFConfiguration(
                    options => options.UseInMemoryDatabase("InMemoryDb"));
                config.AddCommandLine(args);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

该数组跳过索引 #3 的值。 配置绑定程序无法绑定 null 值,也无法在绑定对象中创建 null 条目,这在演示将此数组绑定到对象的结果时变得清晰。

在示例应用中,POCO 类可用于保存绑定的配置数据:

public class ArrayExample
{
    public string[] Entries { get; set; }
}

将配置数据绑定至对象:

var arrayExample = new ArrayExample();
_config.GetSection("array").Bind(arrayExample);

还可以使用 ConfigurationBinder.Get<T> 语法,这样会得到更精简的代码:

ArrayExample = _config.GetSection("array").Get<ArrayExample>();

绑定对象(ArrayExample 的实例)从配置接收数组数据。

ArrayExample.Entries 索引 ArrayExample.Entries
0 value0
1 value1
2 value2
3 value4
4 value5

绑定对象中的索引 #3 保留 array:4 配置键的配置数据及其值 value4 当绑定包含数组的配置数据时,配置键中的数组索引仅用于在创建对象时迭代配置数据。 无法在配置数据中保留 null 值,并且当配置键中的数组跳过一个或多个索引时,不会在绑定对象中创建 null 值条目。

可以在由任何在配置中生成正确键值对的配置提供程序绑定到 ArrayExample 实例之前提供索引 #3 的缺失配置项。 如果示例包含具有缺失键值对的其他 JSON 配置提供程序,则 ArrayExample.Entries 与完整配置数组相匹配:

missing_value.json:

{
  "array:entries:3": "value3"
}

ConfigureAppConfiguration中:

config.AddJsonFile(
    "missing_value.json", optional: false, reloadOnChange: false);

将表中所示的键值对加载到配置中。

“值”
array:entries:3 value3

如果在 JSON 配置提供程序包含索引 #3 的条目之后绑定 ArrayExample 类实例,则 ArrayExample.Entries 数组包含该值。

ArrayExample.Entries 索引 ArrayExample.Entries
0 value0
1 value1
2 value2
3 value3
4 value4
5 value5

JSON 数组处理

如果 JSON 文件包含数组,则会为具有从零开始的节索引的数组元素创建配置键。 在以下配置文件中,subsection 是一个数组:

{
  "json_array": {
    "key": "valueA",
    "subsection": [
      "valueB",
      "valueC",
      "valueD"
    ]
  }
}

JSON 配置提供程序将配置数据读入以下键值对:

“值”
json_array:key valueA
json_array:subsection:0 valueB
json_array:subsection:1 valueC
json_array:subsection:2 valueD

在示例应用中,以下 POCO 类可用于绑定配置键值对:

public class JsonArrayExample
{
    public string Key { get; set; }
    public string[] Subsection { get; set; }
}

绑定后,JsonArrayExample.Key 保存值 valueA 子节值存储在 POCO 数组属性 Subsection 中。

JsonArrayExample.Subsection 索引 JsonArrayExample.Subsection
0 valueB
1 valueC
2 valueD

自定义配置提供程序

该示例应用演示了如何使用实体框架 (EF) 创建从数据库读取配置键值对的基本配置提供程序。

提供程序具有以下特征:

  • EF 内存中数据库用于演示目的。 若要使用需要连接字符串的数据库,请实现辅助 ConfigurationBuilder 以从另一个配置提供程序提供连接字符串。
  • 提供程序在启动时将数据库表读入配置。 提供程序不会基于每个键查询数据库。
  • 未实现更改时重载,因此在应用启动后更新数据库对应用的配置没有任何影响。

定义用于在数据库中存储配置值的 EFConfigurationValue 实体。

Models/EFConfigurationValue.cs

public class EFConfigurationValue
{
    public string Id { get; set; }
    public string Value { get; set; }
}

添加 EFConfigurationContext 以存储和访问配置的值。

EFConfigurationProvider/EFConfigurationContext.cs

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

    public DbSet<EFConfigurationValue> Values { get; set; }
}

创建用于实现 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)
    {
        return new EFConfigurationProvider(_optionsAction);
    }
}

通过从 ConfigurationProvider 继承来创建自定义配置提供程序。 当数据库为空时,配置提供程序将对其进行初始化。 由于配置密钥不区分大小写,因此用来初始化数据库的字典是用不区分大小写的比较程序 (StringComparer.OrdinalIgnoreCase) 创建的。

EFConfigurationProvider/EFConfigurationProvider.cs

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

    Action<DbContextOptionsBuilder> OptionsAction { get; }

    // Load config data from EF DB.
    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
        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 :

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

下面的代码演示如何在 Program.cs 中使用自定义的 EFConfigurationProvider

public class Program
{
    public static Dictionary<string, string> arrayDict = 
        new Dictionary<string, string>
        {
            {"array:entries:0", "value0"},
            {"array:entries:1", "value1"},
            {"array:entries:2", "value2"},
            {"array:entries:4", "value4"},
            {"array:entries:5", "value5"}
        };

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

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddInMemoryCollection(arrayDict);
                config.AddJsonFile(
                    "json_array.json", optional: false, reloadOnChange: false);
                config.AddJsonFile(
                    "starship.json", optional: false, reloadOnChange: false);
                config.AddXmlFile(
                    "tvshow.xml", optional: false, reloadOnChange: false);
                config.AddEFConfiguration(
                    options => options.UseInMemoryDatabase("InMemoryDb"));
                config.AddCommandLine(args);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

在启动期间访问配置

IConfiguration 注入 Startup 构造函数以访问 Startup.ConfigureServices 中的配置值。 若要访问 Startup.Configure 中的配置,请将 IConfiguration 直接注入方法或使用构造函数中的实例:

public class Startup
{
    private readonly IConfiguration _config;

    public Startup(IConfiguration config)
    {
        _config = config;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        var value = _config["key"];
    }

    public void Configure(IApplicationBuilder app, IConfiguration config)
    {
        var value = config["key"];
    }
}

有关使用启动便捷方法访问配置的示例,请参阅应用启动:便捷方法

在 Razor Pages 页或 MVC 视图中访问配置

若要访问 Razor Pages 页或 MVC 视图中的配置设置,请为 Microsoft.Extensions.Configuration 命名空间添加 using 指令C# 参考:using 指令)并将 IConfiguration 注入页面或视图。

在 Razor 页面页中:

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

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Index Page</title>
</head>
<body>
    <h1>Access configuration in a Razor Pages page</h1>
    <p>Configuration value for 'key': @Configuration["key"]</p>
</body>
</html>

在 MVC 视图中:

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Index View</title>
</head>
<body>
    <h1>Access configuration in an MVC view</h1>
    <p>Configuration value for 'key': @Configuration["key"]</p>
</body>
</html>

从外部程序集添加配置

通过 IHostingStartup 实现,可在启动时从应用 Startup 类之外的外部程序集向应用添加增强功能。 有关详细信息,请参阅 在 ASP.NET Core 中使用承载启动程序集

其他资源

ASP.NET Core 中的应用配置基于配置提供程序 建立的键值对。 配置提供程序将配置数据从各种配置源读取到键值对:

  • Azure Key Vault
  • Azure 应用程序配置
  • 命令行参数
  • (已安装或已创建的)自定义提供程序
  • 目录文件
  • 环境变量
  • 内存中的 .NET 对象
  • 设置文件

Microsoft.AspNetCore.App metapackage 中包含通用配置提供程序方案的配置包 (Microsoft Extensions.Configuration)。

后面的代码示例和示例应用中的代码示例使用 Microsoft.Extensions.Configuration 命名空间:

using Microsoft.Extensions.Configuration;

选项模式 是本主题中描述的配置概念的扩展。 选项使用类来表示相关设置的组。 有关详细信息,请参阅 ASP.NET Core 中的选项模式

查看或下载示例代码如何下载

主机与应用配置

在配置并启动应用之前,配置并启动主机 。 主机负责应用程序启动和生存期管理。 应用和主机均使用本主题中所述的配置提供程序进行配置。 应用的配置中也包含主机配置键值对。 有关在构建主机时如何使用配置提供程序以及配置源如何影响主机配置的详细信息,请参阅 ASP.NET Core 基础知识

其他配置

本主题仅与应用配置相关 。 运行和托管 ASP.NET Core 应用的其他方面是使用本主题中未包含的配置文件进行配置:

若要详细了解如何从旧版 ASP.NET 迁移应用配置,请参阅 从 ASP.NET 迁移到 ASP.NET Core

默认配置

基于 ASP.NET Core dotnet new模板的 Web 应用在生成主机时会调用 CreateDefaultBuilder CreateDefaultBuilder 按照以下顺序为应用提供默认配置:

以下内容适用于使用 Web 主机的应用。 有关使用通用主机时默认配置的详细信息,请参阅本主题的最新版本

安全性

采用以下做法来保护敏感配置数据:

  • 请勿在配置提供程序代码或纯文本配置文件中存储密码或其他敏感数据。
  • 不要在开发或测试环境中使用生产机密。
  • 请在项目外部指定机密,避免将其意外提交到源代码存储库。

有关详细信息,请参阅下列主题:

Azure Key Vault 安全存储 ASP.NET Core 应用的应用机密。 有关详细信息,请参阅 ASP.NET Core 中的 Azure Key Vault 配置提供程序

分层配置数据

配置 API 能够通过在配置键中使用分隔符来展平分层数据以保持分层配置数据。

在以下 JSON 文件中,两个节的结构化层次结构中存在四个键:

{
  "section0": {
    "key0": "value",
    "key1": "value"
  },
  "section1": {
    "key0": "value",
    "key1": "value"
  }
}

将文件读入配置时,将创建唯一键以保持配置源的原始分层数据结构。 使用冒号 (:) 展平节和键以保持原始结构:

  • section0:key0
  • section0:key1
  • section1:key0
  • section1:key1

GetSectionGetChildren 方法可用于隔离各个节和配置数据中某节的子节。 稍后将在 GetSection、GetChildren 和 Exists 中介绍这些方法。

约定

源和提供程序

在应用启动时,将按照指定的配置提供程序的顺序读取配置源。

实现更改检测的配置提供程序能够在基础设置更改时重新加载配置。 例如,文件配置提供程序(本主题后面将对此进行介绍)和 Azure Key Vault 配置提供程序实现更改检测。

应用的依赖关系注入 (DI) 容器中提供了 IConfiguration IConfiguration 可注入到 Razor Pages PageModel 或 MVC Controller 来获取以下类的配置。

在下面的示例中,使用 _config 字段来访问配置值:

public class IndexModel : PageModel
{
    private readonly IConfiguration _config;

    public IndexModel(IConfiguration config)
    {
        _config = config;
    }
}
public class HomeController : Controller
{
    private readonly IConfiguration _config;

    public HomeController(IConfiguration config)
    {
        _config = config;
    }
}

配置提供程序不能使用 DI,因为主机在设置这些提供程序时 DI 不可用。

配置键采用以下约定:

  • 键不区分大小写。 例如,ConnectionStringconnectionstring 被视为等效键。
  • 如果由相同或不同的配置提供程序设置相同键的值,则键上设置的最后一个值就是所使用的值。
  • 分层键
    • 在配置 API 中,冒号分隔符 (:) 适用于所有平台。
    • 在环境变量中,冒号分隔符可能无法适用于所有平台。 所有平台均支持采用双下划线 (__),并可以将其自动转换为冒号。
    • 在 Azure Key Vault 中,分层键使用 --(两个破折号)作为分隔符。 将机密加载到应用的配置中时,用冒号替换破折号。
  • ConfigurationBinder 支持使用配置键中的数组索引将数组绑定到对象。 数组绑定将在将数组绑定到类部分中进行介绍。

配置值采用以下约定:

  • 值是字符串。
  • NULL 值不能存储在配置中或绑定到对象。

提供程序

下表显示了 ASP.NET Core 应用可用的配置提供程序。

提供程序 通过以下对象提供配置…
Azure Key Vault 配置提供程序(安全 主题) Azure Key Vault
Azure 应用程序配置提供程序(Azure 文档) Azure 应用程序配置
命令行配置提供程序 命令行参数
自定义配置提供程序 自定义源
环境变量配置提供程序 环境变量
文件配置提供程序 文件(INI、JSON、XML)
Key-per-file 配置提供程序 目录文件
内存配置提供程序 内存中集合
用户机密 (Secret Manager)(安全 主题) 用户配置文件目录中的文件

按照启动时指定的配置提供程序的顺序读取配置源。 本主题中所述的配置提供程序按字母顺序进行介绍,而不是按代码排列顺序进行介绍。 代码中的配置提供程序应以特定顺序排列,从而满足应用所需的基础配置源的优先级。

配置提供程序的典型顺序为:

  1. 文件(appsettings.json、appsettings.{Environment}.json,其中 {Environment} 是应用的当前托管环境)
  2. Azure 密钥保管库
  3. 用户机密 (Secret Manager)(仅限开发环境中)
  4. 环境变量
  5. 命令行参数

通常的做法是将命令行配置提供程序置于一系列提供程序的末尾,以允许命令行参数替代由其他提供程序设置的配置。

使用 CreateDefaultBuilder 初始化新的主机生成器时,将使用上述提供程序序列。 有关详细信息,请参阅默认配置部分。

用 UseConfiguration 配置主机生成器

若要配置主机生成器,请使用配置在主机生成器上调用 UseConfiguration

public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
    var dict = new Dictionary<string, string>
    {
        {"MemoryCollectionKey1", "value1"},
        {"MemoryCollectionKey2", "value2"}
    };

    var config = new ConfigurationBuilder()
        .AddInMemoryCollection(dict)
        .Build();

    return WebHost.CreateDefaultBuilder(args)
        .UseConfiguration(config)
        .UseStartup<Startup>();
}

ConfigureAppConfiguration

构建主机时调用 ConfigureAppConfiguration 以指定应用的配置提供程序以及 CreateDefaultBuilder 自动添加的配置提供程序:

public class Program
{
    public static Dictionary<string, string> arrayDict = 
        new Dictionary<string, string>
        {
            {"array:entries:0", "value0"},
            {"array:entries:1", "value1"},
            {"array:entries:2", "value2"},
            {"array:entries:4", "value4"},
            {"array:entries:5", "value5"}
        };

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

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddInMemoryCollection(arrayDict);
                config.AddJsonFile(
                    "json_array.json", optional: false, reloadOnChange: false);
                config.AddJsonFile(
                    "starship.json", optional: false, reloadOnChange: false);
                config.AddXmlFile(
                    "tvshow.xml", optional: false, reloadOnChange: false);
                config.AddEFConfiguration(
                    options => options.UseInMemoryDatabase("InMemoryDb"));
                config.AddCommandLine(args);
            })
            .UseStartup<Startup>();
}

用命令行参数替代以前的配置

若要提供命令行参数可替代的应用配置,最后请调用 AddCommandLine

.ConfigureAppConfiguration((hostingContext, config) =>
{
    // Call other providers here
    config.AddCommandLine(args);
})

删除 CreateDefaultBuilder 添加的提供程序

要删除 CreateDefaultBuilder 添加的提供程序,请先对 IConfigurationBuilder.Sources 调用 Clear

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.Sources.Clear();
    // Add providers here
})

在应用启动期间使用配置

在应用启动期间,可以使用 ConfigureAppConfiguration 中提供给应用的配置,包括 Startup.ConfigureServices 有关详细信息,请参阅在启动期间访问配置部分。

命令行配置提供程序

CommandLineConfigurationProvider 在运行时从命令行参数键值对加载配置。

要激活命令行配置,请在 ConfigurationBuilder 的实例上调用 AddCommandLine 扩展方法。

调用 CreateDefaultBuilder(string []) 时会自动调用 AddCommandLine 有关详细信息,请参阅默认配置部分。

此外,CreateDefaultBuilder 也会加载:

  • appsettings.json 和 appsettings.{Environment}.json 文件中的可选配置 。
  • 用户机密 (Secret Manager)(在开发环境中)。
  • 环境变量。

CreateDefaultBuilder 最后添加命令行配置提供程序。 在运行时传递的命令行参数会替代由其他提供程序设置的配置。

CreateDefaultBuilder 在构造主机时起作用。 因此,CreateDefaultBuilder 激活的命令行配置可能会影响主机的配置方式。

对于基于 ASP.NET Core 模板的应用,CreateDefaultBuilder 已调用 AddCommandLine 若要添加其他配置提供程序并保持能够用命令行参数替代这些提供程序的配置,请在 ConfigureAppConfiguration 中调用应用的其他提供程序,并最后调用 AddCommandLine

.ConfigureAppConfiguration((hostingContext, config) =>
{
    // Call other providers here
    config.AddCommandLine(args);
})

示例

示例应用利用静态便捷方法 CreateDefaultBuilder 来生成主机,其中包括一个对 AddCommandLine 的调用。

  1. 在项目的目录中打开命令提示符。
  2. dotnet run 命令提供命令行参数 dotnet run CommandLineKey=CommandLineValue
  3. 应用运行后,在 http://localhost:5000 打开应用的浏览器。
  4. 观察输出是否包含提供给 dotnet run 的配置命令行参数的键值对。

自变量

该值必须后跟一个等号 (=),否则当值后跟一个空格时,键必须具有前缀(--/)。 如果使用等号(例如 CommandLineKey=),则不需要该值。

键前缀 示例
无前缀 CommandLineKey1=value1
双划线 (--) --CommandLineKey2=value2--CommandLineKey2 value2
正斜杠 (/) /CommandLineKey3=value3/CommandLineKey3 value3

在同一命令中,不要将使用等号的命令行参数键值对与使用空格的键值对混合使用。

示例命令:

dotnet run CommandLineKey1=value1 --CommandLineKey2=value2 /CommandLineKey3=value3
dotnet run --CommandLineKey1 value1 /CommandLineKey2 value2
dotnet run CommandLineKey1= CommandLineKey2=value2

交换映射

交换映射支持键名替换逻辑。 使用 ConfigurationBuilder 手动构建配置时,需要为 AddCommandLine 方法提供交换替换字典。

当使用交换映射字典时,会检查字典中是否有与命令行参数提供的键匹配的键。 如果在字典中找到命令行键,则传回字典值(键替换)以将键值对设置为应用的配置。 对任何具有单划线 (-) 前缀的命令行键而言,交换映射都是必需的。

交换映射字典键规则:

  • 交换必须以单划线 (-) 或双划线 (--) 开头。
  • 交换映射字典不得包含重复键。

创建交换映射字典。 在以下示例中,创建了两个交换映射:

public static readonly Dictionary<string, string> _switchMappings = 
    new Dictionary<string, string>
    {
        { "-CLKey1", "CommandLineKey1" },
        { "-CLKey2", "CommandLineKey2" }
    };

生成主机后,使用交换映射字典来调用 AddCommandLine

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddCommandLine(args, _switchMappings);
})

对于使用交换映射的应用,调用 CreateDefaultBuilder 不应传递参数。 CreateDefaultBuilder 方法的 AddCommandLine 调用不包括映射的交换,并且无法将交换映射字典传递给 CreateDefaultBuilder 解决方案不是将参数传递给 CreateDefaultBuilder,而是允许 ConfigurationBuilder 方法的 AddCommandLine 方法处理参数和交换映射字典。

创建交换映射字典后,它将包含下表所示的数据。

“值”
-CLKey1 CommandLineKey1
-CLKey2 CommandLineKey2

如果在启动应用时使用了交换映射的键,则配置将接收字典提供的密钥上的配置值:

dotnet run -CLKey1=value1 -CLKey2=value2

运行上述命令后,配置包含下表中显示的值。

“值”
CommandLineKey1 value1
CommandLineKey2 value2

环境变量配置提供程序

EnvironmentVariablesConfigurationProvider 在运行时从环境变量键值对加载配置。

要激活环境变量配置,请在 ConfigurationBuilder 的实例上调用 AddEnvironmentVariables 扩展方法。

在环境变量中使用分层键时,冒号分隔符 (:) 可能无法适用于所有平台(例如 Bash)。 所有平台均支持采用双下划线 (__),并可以用冒号自动替换。

借助 Azure 应用服务,可在 Azure 门户中设置使用环境变量配置提供程序替代应用配置的环境变量。 有关详细信息,请参阅 Azure 应用:使用 Azure 门户替代应用配置

如果使用 Web 主机初始化新的主机生成器,且调用 CreateDefaultBuilder,则使用 AddEnvironmentVariables主机配置加载前缀为 ASPNETCORE_ 的环境变量。 有关详细信息,请参阅默认配置部分。

此外,CreateDefaultBuilder 也会加载:

  • 来自没有前缀的环境变量的应用配置,方法是通过调用不带前缀的 AddEnvironmentVariables
  • appsettings.json 和 appsettings.{Environment}.json 文件中的可选配置 。
  • 用户机密 (Secret Manager)(在开发环境中)。
  • 命令行参数。

环境变量配置提供程序是在配置已根据用户机密和 appsettings 文件建立后调用。 在此位置调用提供程序允许在运行时读取的环境变量替代由用户机密和 appsettings 文件设置的配置。

要从其他环境变量提供应用配置,请在 ConfigureAppConfiguration 中调用应用的其他提供程序,并使用前缀调用 AddEnvironmentVariables

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddEnvironmentVariables(prefix: "PREFIX_");
})

最后调用 AddEnvironmentVariables让带给定前缀的环境变量可替代其他提供程序中的值。

示例

示例应用利用静态便捷方法 CreateDefaultBuilder 来生成主机,其中包括一个对 AddEnvironmentVariables 的调用。

  1. 运行示例应用。 http://localhost:5000 打开应用的浏览器。
  2. 观察输出是否包含环境变量 ENVIRONMENT 的键值对。 该值反映了应用运行的环境,在本地运行时通常为 Development

为了缩短应用呈现的环境变量列表,应用会筛选环境变量。 请参阅示例应用的“Pages/Index.cshtml.cs”文件 。

要公开应用可用的所有环境变量,请将 Pages/Index.cshtml.cs 中的 FilteredConfiguration 更改为以下内容 :

FilteredConfiguration = _config.AsEnumerable();

前缀

AddEnvironmentVariables 方法提供前缀时,将筛选加载到应用的配置中的环境变量。 例如,要筛选前缀 CUSTOM_ 上的环境变量,请将前缀提供给配置提供程序:

var config = new ConfigurationBuilder()
    .AddEnvironmentVariables("CUSTOM_")
    .Build();

创建配置键值对时,将去除前缀。

若已创建主机生成器,则主机配置由环境变量提供。 有关用于这些环境变量的前缀的详细信息,请参阅默认配置部分。

连接字符串前缀

针对为应用环境配置 Azure 连接字符串所涉及的四个连接字符串环境变量,配置 API 具有特殊的处理规则。 如果没有向 AddEnvironmentVariables 提供前缀,则具有表中所示前缀的环境变量将加载到应用中。

连接字符串前缀 提供程序
CUSTOMCONNSTR_ 自定义提供程序
MYSQLCONNSTR_ MySQL
SQLAZURECONNSTR_ Azure SQL 数据库
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

示例

在服务器上创建了一个自定义连接字符串环境变量:

  • 名称 – CUSTOMCONNSTR_ReleaseDB
  • 值 – Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True

如果 IConfiguration 已引入并分配给名为 _config 的字段,请读取值:

_config["ConnectionStrings:ReleaseDB"]

文件配置提供程序

FileConfigurationProvider 是从文件系统加载配置的基类。 以下配置提供程序专用于特定文件类型:

INI 配置提供程序

IniConfigurationProvider 在运行时从 INI 文件键值对加载配置。

若要激活 INI 文件配置,请在 ConfigurationBuilder 的实例上调用 AddIniFile 扩展方法。

冒号可用作 INI 文件配置中的节分隔符。

重载允许指定:

  • 文件是否可选。
  • 如果文件更改,是否重载配置。
  • IFileProvider 用于访问该文件。

构建主机时调用 ConfigureAppConfiguration 以指定应用的配置:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddIniFile(
        "config.ini", optional: true, reloadOnChange: true);
})

INI 配置文件的通用示例:

[section0]
key0=value
key1=value

[section1]
subsection:key=value

[section2:subsection0]
key=value

[section2:subsection1]
key=value

以前的配置文件使用 value 加载以下键:

  • section0:key0
  • section0:key1
  • section1:subsection:key
  • section2:subsection0:key
  • section2:subsection1:key

JSON 配置提供程序

JsonConfigurationProvider 在运行时期间从 JSON 文件键值对加载配置。

若要激活 JSON 文件配置,请在 ConfigurationBuilder 的实例上调用 AddJsonFile 扩展方法。

重载允许指定:

  • 文件是否可选。
  • 如果文件更改,是否重载配置。
  • IFileProvider 用于访问该文件。

使用 CreateDefaultBuilder 初始化新的主机生成器时,会自动调用两次 AddJsonFile 调用该方法来从以下文件加载配置:

  • appsettings.json – 首先读取此文件 。 该文件的环境版本可以替代 appsettings.json 文件提供的值。
  • appsettings.{Environment}.json – 根据 IHostingEnvironment.EnvironmentName 加载文件的环境版本 。

有关详细信息,请参阅默认配置部分。

此外,CreateDefaultBuilder 也会加载:

首先建立 JSON 配置提供程序。 因此,用户机密、环境变量和命令行参数会替代由 appsettings 文件设置的配置。

构建主机时调用 ConfigureAppConfiguration 以指定除 appsettings.json 和 appsettings.{Environment}.json 以外的文件的应用配置:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddJsonFile(
        "config.json", optional: true, reloadOnChange: true);
})

示例

示例应用利用静态便捷方法 CreateDefaultBuilder 来生成主机,其中包括两个对 AddJsonFile 的调用:

  • 第一次调用 AddJsonFile 会从 appsettings 加载配置 :

    {
      "Logging": {
        "LogLevel": {
          "Default": "Warning"
        }
      },
      "AllowedHosts": "*"
    }
    
  • 第二次调用 AddJsonFile 会从 appsettings.{Environment}.json 加载配置 。 对于示例应用中的 appsettings.Development.json,将加载以下文件 :

    {
      "Logging": {
        "LogLevel": {
          "Default": "Debug",
          "System": "Information",
          "Microsoft": "Information"
        }
      }
    }
    
  1. 运行示例应用。 http://localhost:5000 打开应用的浏览器。
  2. 输出包含配置的键值对(由应用的环境而定)。 在开发环境中运行应用时,键 Logging:LogLevel:Default 的日志级别为 Debug
  3. 再次在生产环境中运行示例应用:
    1. 打开 Properties/launchSettings.json 文件 。
    2. ConfigurationSample 配置文件中,将 ASPNETCORE_ENVIRONMENT 环境变量的值更改为 Production
    3. 保存文件,然后在命令外壳中使用 dotnet run 运行应用。
  4. appsettings.Development.json 中的设置不再替代 appsettings.json 中的设置 。 Logging:LogLevel:Default 的日志级别为 Warning

XML 配置提供程序

XmlConfigurationProvider 在运行时从 XML 文件键值对加载配置。

若要激活 XML 文件配置,请在 ConfigurationBuilder 的实例上调用 AddXmlFile 扩展方法。

重载允许指定:

  • 文件是否可选。
  • 如果文件更改,是否重载配置。
  • IFileProvider 用于访问该文件。

创建配置键值对时,将忽略配置文件的根节点。 不要在文件中指定文档类型定义 (DTD) 或命名空间。

构建主机时调用 ConfigureAppConfiguration 以指定应用的配置:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddXmlFile(
        "config.xml", optional: true, reloadOnChange: true);
})

XML 配置文件可以为重复节使用不同的元素名称:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <section0>
    <key0>value</key0>
    <key1>value</key1>
  </section0>
  <section1>
    <key0>value</key0>
    <key1>value</key1>
  </section1>
</configuration>

以前的配置文件使用 value 加载以下键:

  • section0:key0
  • section0:key1
  • section1:key0
  • section1:key1

如果使用 name 属性来区分元素,则使用相同元素名称的重复元素可以正常工作:

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

以前的配置文件使用 value 加载以下键:

  • section:section0:key:key0
  • section:section0:key:key1
  • section:section1:key:key0
  • section:section1:key:key1

属性可用于提供值:

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

以前的配置文件使用 value 加载以下键:

  • key:attribute
  • section:key:attribute

Key-per-file 配置提供程序

KeyPerFileConfigurationProvider 使用目录的文件作为配置键值对。 该键是文件名。 该值包含文件的内容。 Key-per-file 配置提供程序用于 Docker 托管方案。

若要激活 Key-per-file 配置,请在 ConfigurationBuilder 的实例上调用 AddKeyPerFile 扩展方法。 文件的 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 使用内存中集合作为配置键值对。

若要激活内存中集合配置,请在 ConfigurationBuilder 的实例上调用 AddInMemoryCollection 扩展方法。

可以使用 IEnumerable<KeyValuePair<String,String>> 初始化配置提供程序。

构建主机时调用 ConfigureAppConfiguration 以指定应用的配置。

在下面的示例中,创建了配置字典:

public static readonly Dictionary<string, string> _dict = 
    new Dictionary<string, string>
    {
        {"MemoryCollectionKey1", "value1"},
        {"MemoryCollectionKey2", "value2"}
    };

通过 AddInMemoryCollection 的调用使用字典,以提供配置:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddInMemoryCollection(_dict);
})

GetValue

ConfigurationBinder.GetValueT<> 从配置中提取一个具有指定键的值,并将其转换为指定的非集合类型。 重载接受默认值。

如下示例中:

  • 使用键 NumberKey 从配置中提取字符串值。 如果在配置键中找不到 NumberKey,则使用默认值 99
  • 键入值作为 int
  • 存储 NumberConfig 属性中的值,以供页面使用。
public class IndexModel : PageModel
{
    public IndexModel(IConfiguration config)
    {
        _config = config;
    }

    public int NumberConfig { get; private set; }

    public void OnGet()
    {
        NumberConfig = _config.GetValue<int>("NumberKey", 99);
    }
}

GetSection、GetChildren 和 Exists

对于下面的示例,请考虑以下 JSON 文件。 在两个节中找到四个键,其中一个包含一对子节:

{
  "section0": {
    "key0": "value",
    "key1": "value"
  },
  "section1": {
    "key0": "value",
    "key1": "value"
  },
  "section2": {
    "subsection0" : {
      "key0": "value",
      "key1": "value"
    },
    "subsection1" : {
      "key0": "value",
      "key1": "value"
    }
  }
}

将文件读入配置时,会创建以下唯一的分层键来保存配置值:

  • section0:key0
  • section0:key1
  • section1:key0
  • section1:key1
  • section2:subsection0:key0
  • section2:subsection0:key1
  • section2:subsection1:key0
  • section2:subsection1:key1

GetSection

IConfiguration.GetSection 使用指定的子节键提取配置子节。

若要返回仅包含 section1 中键值对的 IConfigurationSection,请调用 GetSection 并提供节名称:

var configSection = _config.GetSection("section1");

configSection 不具有值,只有密钥和路径。

同样,若要获取 section2:subsection0 中键的值,请调用 GetSection 并提供节路径:

var configSection = _config.GetSection("section2:subsection0");

GetSection 永远不会返回 null 如果找不到匹配的节,则返回空 IConfigurationSection

GetSection 返回匹配的部分时,Value 未填充。 存在该部分时,返回一个 KeyPath 部分。

GetChildren

section2 上调用 IConfiguration.GetChildren 会获得 IEnumerable<IConfigurationSection>,其中包括:

  • subsection0
  • subsection1
var configSection = _config.GetSection("section2");

var children = configSection.GetChildren();

存在

使用 ConfigurationExtensions.Exists 确定配置节是否存在:

var sectionExists = _config.GetSection("section2:subsection2").Exists();

给定示例数据,sectionExistsfalse,因为配置数据中没有 section2:subsection2 节。

绑定至类

可以使用选项模式 将配置绑定到表示相关设置组的类。 有关详细信息,请参阅 ASP.NET Core 中的选项模式

配置值作为字符串返回,但调用 Bind 可以构造 POCO 对象。 绑定器将值绑定到所提供类型的所有公共读取/写入属性。 不会绑定字段 。

示例应用包含 Starship 模型 (Models/Starship.cs ):

public class Starship
{
    public string Name { get; set; }
    public string Registry { get; set; }
    public string Class { get; set; }
    public decimal Length { get; set; }
    public bool Commissioned { get; set; }
}

当示例应用使用 JSON 配置提供程序加载配置时,starship.json 文件的 starship 节会创建配置:

{
  "starship": {
    "name": "USS Enterprise",
    "registry": "NCC-1701",
    "class": "Constitution",
    "length": 304.8,
    "commissioned": false
  },
  "trademark": "Paramount Pictures Corp. http://www.paramount.com"
}

创建以下配置键值对:

“值”
starship:name USS Enterprise
starship:registry NCC-1701
starship:class Constitution
starship:length 304.8
starship:commissioned False
trademark Paramount Pictures Corp. https://www.paramount.com

示例应用使用 starship 键调用 GetSection starship 键值对是独立的。 在子节传入 Starship 类的实例时调用 Bind 方法。 绑定实例值后,将实例分配给用于呈现的属性:

var starship = new Starship();
_config.GetSection("starship").Bind(starship);
Starship = starship;

绑定至对象图

Bind 能够绑定整个 POCO 对象图。 与绑定简单对象一样,只绑定公共读取/写入属性。

该示例包含 TvShow 模型,其对象图包含 MetadataActors 类 (Models/TvShow.cs ):

public class TvShow
{
    public Metadata Metadata { get; set; }
    public Actors Actors { get; set; }
    public string Legal { get; set; }
}

public class Metadata
{
    public string Series { get; set; }
    public string Title { get; set; }
    public DateTime AirDate { get; set; }
    public int Episodes { get; set; }
}

public class Actors
{
    public string Names { get; set; }
}

示例应用有一个包含配置数据的 tvshow.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <tvshow>
    <metadata>
      <series>Dr. Who</series>
      <title>The Sun Makers</title>
      <airdate>11/26/1977</airdate>
      <episodes>4</episodes>
    </metadata>
    <actors>
      <names>Tom Baker, Louise Jameson, John Leeson</names>
    </actors>
    <legal>(c)1977 BBC https://www.bbc.co.uk/programmes/b006q2x0</legal>
  </tvshow>
</configuration>

使用 Bind 方法将配置绑定到整个 TvShow 对象图。 将绑定实例分配给用于呈现的属性:

var tvShow = new TvShow();
_config.GetSection("tvshow").Bind(tvShow);
TvShow = tvShow;

ConfigurationBinder.Get<T> 绑定并返回指定类型。 Get<T> 比使用 Bind 更方便。 以下代码显示如何将 Get<T> 与前面的示例一起使用,该示例允许将绑定实例直接分配给用于呈现的属性:

TvShow = _config.GetSection("tvshow").Get<TvShow>();

将数组绑定至类

示例应用演示了本部分中介绍的概念。

Bind 支持使用配置键中的数组索引将数组绑定到对象。 公开数字键段(:0::1:、… :{n}:)的任何数组格式都能够与 POCO 类数组进行数组绑定。

备注

绑定是按约定提供的。 不需要自定义配置提供程序实现数组绑定。

内存中数组处理

请考虑下表中所示的配置键和值。

“值”
array:entries:0 value0
array:entries:1 value1
array:entries:2 value2
array:entries:4 value4
array:entries:5 value5

使用内存配置提供程序在示例应用中加载这些键和值:

public class Program
{
    public static Dictionary<string, string> arrayDict = 
        new Dictionary<string, string>
        {
            {"array:entries:0", "value0"},
            {"array:entries:1", "value1"},
            {"array:entries:2", "value2"},
            {"array:entries:4", "value4"},
            {"array:entries:5", "value5"}
        };

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

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddInMemoryCollection(arrayDict);
                config.AddJsonFile(
                    "json_array.json", optional: false, reloadOnChange: false);
                config.AddJsonFile(
                    "starship.json", optional: false, reloadOnChange: false);
                config.AddXmlFile(
                    "tvshow.xml", optional: false, reloadOnChange: false);
                config.AddEFConfiguration(
                    options => options.UseInMemoryDatabase("InMemoryDb"));
                config.AddCommandLine(args);
            })
            .UseStartup<Startup>();
}

该数组跳过索引 #3 的值。 配置绑定程序无法绑定 null 值,也无法在绑定对象中创建 null 条目,这在演示将此数组绑定到对象的结果时变得清晰。

在示例应用中,POCO 类可用于保存绑定的配置数据:

public class ArrayExample
{
    public string[] Entries { get; set; }
}

将配置数据绑定至对象:

var arrayExample = new ArrayExample();
_config.GetSection("array").Bind(arrayExample);

还可以使用 ConfigurationBinder.Get<T> 语法,这样会得到更精简的代码:

ArrayExample = _config.GetSection("array").Get<ArrayExample>();

绑定对象(ArrayExample 的实例)从配置接收数组数据。

ArrayExample.Entries 索引 ArrayExample.Entries
0 value0
1 value1
2 value2
3 value4
4 value5

绑定对象中的索引 #3 保留 array:4 配置键的配置数据及其值 value4 当绑定包含数组的配置数据时,配置键中的数组索引仅用于在创建对象时迭代配置数据。 无法在配置数据中保留 null 值,并且当配置键中的数组跳过一个或多个索引时,不会在绑定对象中创建 null 值条目。

可以在由任何在配置中生成正确键值对的配置提供程序绑定到 ArrayExample 实例之前提供索引 #3 的缺失配置项。 如果示例包含具有缺失键值对的其他 JSON 配置提供程序,则 ArrayExample.Entries 与完整配置数组相匹配:

missing_value.json:

{
  "array:entries:3": "value3"
}

ConfigureAppConfiguration中:

config.AddJsonFile(
    "missing_value.json", optional: false, reloadOnChange: false);

将表中所示的键值对加载到配置中。

“值”
array:entries:3 value3

如果在 JSON 配置提供程序包含索引 #3 的条目之后绑定 ArrayExample 类实例,则 ArrayExample.Entries 数组包含该值。

ArrayExample.Entries 索引 ArrayExample.Entries
0 value0
1 value1
2 value2
3 value3
4 value4
5 value5

JSON 数组处理

如果 JSON 文件包含数组,则会为具有从零开始的节索引的数组元素创建配置键。 在以下配置文件中,subsection 是一个数组:

{
  "json_array": {
    "key": "valueA",
    "subsection": [
      "valueB",
      "valueC",
      "valueD"
    ]
  }
}

JSON 配置提供程序将配置数据读入以下键值对:

“值”
json_array:key valueA
json_array:subsection:0 valueB
json_array:subsection:1 valueC
json_array:subsection:2 valueD

在示例应用中,以下 POCO 类可用于绑定配置键值对:

public class JsonArrayExample
{
    public string Key { get; set; }
    public string[] Subsection { get; set; }
}

绑定后,JsonArrayExample.Key 保存值 valueA 子节值存储在 POCO 数组属性 Subsection 中。

JsonArrayExample.Subsection 索引 JsonArrayExample.Subsection
0 valueB
1 valueC
2 valueD

自定义配置提供程序

该示例应用演示了如何使用实体框架 (EF) 创建从数据库读取配置键值对的基本配置提供程序。

提供程序具有以下特征:

  • EF 内存中数据库用于演示目的。 若要使用需要连接字符串的数据库,请实现辅助 ConfigurationBuilder 以从另一个配置提供程序提供连接字符串。
  • 提供程序在启动时将数据库表读入配置。 提供程序不会基于每个键查询数据库。
  • 未实现更改时重载,因此在应用启动后更新数据库对应用的配置没有任何影响。

定义用于在数据库中存储配置值的 EFConfigurationValue 实体。

Models/EFConfigurationValue.cs

public class EFConfigurationValue
{
    public string Id { get; set; }
    public string Value { get; set; }
}

添加 EFConfigurationContext 以存储和访问配置的值。

EFConfigurationProvider/EFConfigurationContext.cs

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

    public DbSet<EFConfigurationValue> Values { get; set; }
}

创建用于实现 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)
    {
        return new EFConfigurationProvider(_optionsAction);
    }
}

通过从 ConfigurationProvider 继承来创建自定义配置提供程序。 当数据库为空时,配置提供程序将对其进行初始化。

EFConfigurationProvider/EFConfigurationProvider.cs

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

    Action<DbContextOptionsBuilder> OptionsAction { get; }

    // Load config data from EF DB.
    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
        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 :

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

下面的代码演示如何在 Program.cs 中使用自定义的 EFConfigurationProvider

public class Program
{
    public static Dictionary<string, string> arrayDict = 
        new Dictionary<string, string>
        {
            {"array:entries:0", "value0"},
            {"array:entries:1", "value1"},
            {"array:entries:2", "value2"},
            {"array:entries:4", "value4"},
            {"array:entries:5", "value5"}
        };

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

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddInMemoryCollection(arrayDict);
                config.AddJsonFile(
                    "json_array.json", optional: false, reloadOnChange: false);
                config.AddJsonFile(
                    "starship.json", optional: false, reloadOnChange: false);
                config.AddXmlFile(
                    "tvshow.xml", optional: false, reloadOnChange: false);
                config.AddEFConfiguration(
                    options => options.UseInMemoryDatabase("InMemoryDb"));
                config.AddCommandLine(args);
            })
            .UseStartup<Startup>();
}

在启动期间访问配置

IConfiguration 注入 Startup 构造函数以访问 Startup.ConfigureServices 中的配置值。 若要访问 Startup.Configure 中的配置,请将 IConfiguration 直接注入方法或使用构造函数中的实例:

public class Startup
{
    private readonly IConfiguration _config;

    public Startup(IConfiguration config)
    {
        _config = config;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        var value = _config["key"];
    }

    public void Configure(IApplicationBuilder app, IConfiguration config)
    {
        var value = config["key"];
    }
}

有关使用启动便捷方法访问配置的示例,请参阅应用启动:便捷方法

在 Razor Pages 页或 MVC 视图中访问配置

若要访问 Razor Pages 页或 MVC 视图中的配置设置,请为 Microsoft.Extensions.Configuration 命名空间添加 using 指令C# 参考:using 指令)并将 IConfiguration 注入页面或视图。

在 Razor 页面页中:

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

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Index Page</title>
</head>
<body>
    <h1>Access configuration in a Razor Pages page</h1>
    <p>Configuration value for 'key': @Configuration["key"]</p>
</body>
</html>

在 MVC 视图中:

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Index View</title>
</head>
<body>
    <h1>Access configuration in an MVC view</h1>
    <p>Configuration value for 'key': @Configuration["key"]</p>
</body>
</html>

从外部程序集添加配置

通过 IHostingStartup 实现,可在启动时从应用 Startup 类之外的外部程序集向应用添加增强功能。 有关详细信息,请参阅 在 ASP.NET Core 中使用承载启动程序集

其他资源

上一篇:ASP.NET Core 中的 Web 服务器实现

下一篇:ASP.NET Core 中的选项模式

关注微信小程序
程序员编程王-随时随地学编程

扫描二维码
程序员编程王

扫一扫关注最新编程教程