ASP.NET Core 中的配置 【上】

此为系列文章,对MSDN ASP.NET Core 的官方文档进行系统学习与翻译。其中或许会添加本人对 ASP.NET Core 的浅显理解。 

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

  • Azure密钥库
  • Azure应用程序配置
  • 命令行参数
  • 自定义提供器(装载的或者新建的)
  • 字典文件
  • 环境变量
  • 内存中.NET对象
  • 设置文件

       通用配置提供器场景的配置Pakages隐式的包含在框架中。

       接下来以及在示例中的代码使用了Microsoft.Extensions.Configuration 命名空间。

using Microsoft.Extensions.Configuration;

       选项模式是本章描述的配置概念的一个扩展。选项模式使用类来代表一组相关的配置。更多信息,请参考Options pattern in ASP.NET Core

       View or download sample code (how to download)

宿主与App 配置

       在app被配置以及启动之前,一个宿主会被配置和加载。宿主负责app的启动以及生命周期管理。app以及宿主都会使用本章描述的配置提供器进行配置。宿主配置键值对会包含在app配置中。关于在宿主被建立时,配置提供器如何使用以及配置源如何影响宿主配置的更多信息,请参考ASP.NET Core fundamentals

其他配置

      本章主题仅仅适用于app.configration。运行以及寄宿ASP.NET Core apps的其他方面将使用其他配置文件进行配置,其不包含在本章主题之中。

      关于从早期版本的ASP.NET 中迁移配置文件的更多信息,请参考:Migrate from ASP.NET to ASP.NET Core

默认配置

      基于ASP.NET Core dotnet new 模板创建的web app在建立一个宿主的时候会调用CreateDefaultBuilderCreateDefaultBuilder 按照如下顺序为app 提供默认的配置:

      以下内容适用于使用了Generic Host 的app。当使用Web Host时,关于默认配置的更多信息,请参考ASP.NET Core 2.2 version of this topic

安全

      对于安全敏感的配置数据采取以下实践:

  • 绝对不要将密码以及其他敏感数据存储在配置提供器代码中,或者在纯文本配置文件中。
  • 在开发环境以及测试环境中,不要使用生产环境的密钥。
  • 将密钥在项目工程之外指定,这样它们便不会被自动提交给源码库。

       更多信息,请参考如下主题:

        Azure密钥库 为ASP.NET Core app安全的存储app密钥。更多信息,请参考Azure Key Vault Configuration Provider in ASP.NET Core

层次化的配置数据

        配置API可用维护层次化的配置数据,器通过使用配置键中的分号(;)来将层次化的数据扁平化。

        在如下的Json文件中,四个键值存在于两部分组成的结构化的等级制度中。

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

      当文件被读入到配置中,会创建唯一的键值来维护原始的来自于配置源的层次化数据结构。我们使用一个冒号来将部分以及键值进行扁平化处理,以维护原始的数据结构:

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

     GetSection 以及 GetChildren 方法可用来分离开各个部分以及它们的子节点。这些方法在GetSection, GetChildren, and Exists 中会有描述。

惯例

       源以及提供器

       在app启动时,配置源被按照器配置提供器被指定的顺序被读取。

       实现了更新检测的提供器当底层的设置被更新时可以重加载配置。举个例子,文件配置提供器(本章后续会有描述)以及Azure Key Vault Configuration Provider 都实现了更改探测。

      IConfiguration 在app 的DI容器中是可用的。IConfiguration 可以被注入到一个Razor页面的 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还是不可用的。

       键

       配置键值采取了如下约定:

  • 键是大小写不敏感的。举个例子,ConnectionString和connectionstring 被当作相等的键。
  • 如果一个相同键的值被相同或者不同的配置提供器所设置,那么最后一个设置的值将会被使用。
  • 层次化的键值
    • 在配置API之内,冒号分隔符在所有的平台都能工作。
    • 在环境变量中,冒号分隔符可能不能在所有的平台下都能工作。但双下划线(__)会被所有的平台支持,并自动转换为一个冒号。
    • 在Azure密钥库中,层次化的键值使用 (--) 作为一个分隔符。当密钥被加载到app的配置中的时候,需要些代码来使用冒号将(-)替换掉。
  • ConfigurationBinder 支持将数组绑定到对象,数组绑定在Bind an array to a class 章节会有相应的介绍。

     值

     配置值采取如下的约定:

  • 值都是字符串。
  • 空值不能被存储在配置中或者绑定给对象。

提供器

      下列表格展示了ASP.NET Core app中可用的配置提供器:

                                  

ProviderProvides configuration from…
Azure Key Vault Configuration Provider (Security topics) Azure Key Vault
Azure App Configuration Provider (Azure documentation) Azure App Configuration
Command-line Configuration Provider Command-line parameters
Custom configuration provider Custom source
Environment Variables Configuration Provider Environment variables
File Configuration Provider Files (INI, JSON, XML)
Key-per-file Configuration Provider Directory files
Memory Configuration Provider In-memory collections
User secrets (Secret Manager) (Security topics) File in the user profile directory

      在app启动时,配置源按照其配置提供器指定的顺序被读取。本章描述的配置提供器是按照字符顺序,而不是代码安排它们的顺序来描述的。在代码中对配置提供器进行排序以匹配app所需要的底层配置源的优先级。

      一个典型的配置提供器序列是:

  1. 文件(appsettings.json, appsettings.{Environment}.json, 其中{Environment} 是应用程序的当前寄宿环境)
  2. Azure密钥库
  3. 用户密钥(Secret Manager)(仅针对开发环境)
  4. 环境变量
  5. 命令行参数

      一个通用的实践是将命令行配置提供器放置在一系列提供器的最后,以允许命令行参数重载被其他提供器设置的配置。

      当一个新的宿主被使用CreateDefaultBuilder来初始化的时候,上面的提供器序列会被使用。更多 信息,请参考Default configuration 章节。

使用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自动添加的之外其他的app的配置提供器。

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
})

      在app启动时消费配置

      在ConfigureAppConfiguration中提供给app的配置在app的启动阶段是可用的,包括Startup.ConfigureServices方法。更多信息,请参考Access configuration during startup 章节。

命令行配置提供器

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

       为了激活命令行配置,可以在ConfigurationBuilder的实例上调用AddCommandLine 扩展方法。

       当调用CreateDefaultBuilder 方法时,AddCommandLine 方法会被自动调用。更多信息,请参考Default configuration 章节。

       CreateDefaultBuilder 也会加载:

      CreateDefaultBuilder 最后会添加命令行配置提供器。运行时传递的命令行参数会重载被其他提供器设置的配置。

      当宿主被构造时,CreateDefaultBuilder便会行动起来。因此,被CreateDefaultBuilder激活的命令行配置可以影响宿主如何被配置。

      对于基于ASP.NET Core模板的app来说,AddCommandLine 已经被CreateDefaultBuilder 所调用。为了添加额外的配置提供器,并且维护使用命令行参数重载配置的能力,可以在ConfigureAppConfiguration中调用额外的提供器并最后调用AddCommandLine

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

      示例

      示例app使用静态约定方法CreateDefaultBuilder来构建宿主,其包含了一个对AddCommandLine的调用。

  1. 在工程目录中打开一个命令提示符。
  2. dotnet run命令提供命令行参数:dotnet run CommandLineKey=CommandLineValue
  3. app运行之后,打开浏览器:http://localhost:5000
  4. 可以观察到,输出包含了提供给dotnet run命令的键值对。

      参数

      参数值必须跟着一个=,或者当值跟随一个空格时,键值必须有一个前缀(--/),如果使用一个=号时,那么值不是必须的(比如 CommandLineKey=)。

                                

Key prefixExample
No prefix CommandLineKey1=value1
Two dashes (--) --CommandLineKey2=value2, --CommandLineKey2 value2
Forward slash (/) /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 方法提供一个交互替换的字典。

     当交互映射字典被使用时,字典便会检查以寻找与命令行参数提供的键匹配的键。如果命令行键在字典中被 找到,那么字典的值便会回传给app配置以设置键值对。对于任何具有前缀(-)的命令行键,都会需要一个交互映射。

     交互映射字典键的规则:

  • 必须以一个 - 或者 两个 -- 开始。
  • 交互映射字典不能包含重复的键。

     创建一个交互映射字典。在下列示例中,两个交互映射被创建:

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

      当宿主被构造时,使用交互映射字典为参数来调用AddCommandLine:

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

      对于使用交互映射的app来说,对CreateDefaultBuilder 的调用不应该传递参数。CreateDefaultBuilder方法的AddCommandLine 调用不包含映射的交互。并且没有方法来给CreateDefaultBuilder传递交互映射字典。我们的解决方案并不是给CreateDefaultBuilder 传递参数,而是允许ConfigurationBuilder方法的AddCommandLine 方法来处理参数以及交互映射字典。

      在交互映射字典被创建之后,其包含了下表所示的数据:

KeyValue
-CLKey1 CommandLineKey1
-CLKey2 CommandLineKey2

      在app启动时,如果使用了交互映射字典,配置便会在字典提供的键值上接受配置值:

dotnet run -CLKey1=value1 -CLKey2=value2

      运行上面的命令后,配置会包含下表所示的配置值:

Key     Value
CommandLineKey1     value1
CommandLineKey2     value2
原文地址:https://www.cnblogs.com/qianxingmu/p/12504285.html