• asp.net core 系列之Configuration


    ASP.NET Core中的App configuration 是通过configuration providers基于key-value对建立的。Configuration providers读取配置文件到key-value,从多种配置源中:

    • Azure key Vault
    • Command-line arguments
    • Custom providers(installed or created)
    • Directory files
    • Environment variables
    • In-memory .NET objects
    • Setting files

    用于提供Configuration配置的包是包含在Microsoft.AspNetCore.App metapackage里。下面的代码示例,将会使用Microsoft.Extensions.Configuration命名空间。

    using Microsoft.Extensions.Configuration;

    一.概述

    1.Host vs App configuration(对比)

    在应用配置和启动之前,host被配置和launched(发动,开展)Host 负责应用的startup和生命周期管理。应用和主机都是用这个主题描述的configuration providers来配置。主机配置的key-values对成为应用全局配置的一部分。

    2.Default configuration

    ASP.NET Core基础上的Web应用 dotnet new templates(模板)会调用CreateDefaultBuilder,当建立host时,CreateDefaultBuilder为应用提供默认的配置,以下面的顺序

    (1).主机配置是被下面这些提供的:

    • ASPNETCORE_为前缀的环境变量(例如,ASPNETCORE_ENVIRONMENT)使用Environment Variables Configuration Provider. configuration key-values对被加载时,前缀(ASPNETCORE_)被去掉。
    • 命令行参数使用Command-line Configuration Provider提供

    (2).应用配置是被下面这些提供的:

    • appsettings.json使用File Configuration Provider提供
    • appsetting.{Environment}.json使用File Configuration Provider提供
    • 当应用运行在Development environment(开发环境), Secret Manager使用entry程序(entry:入口)
    • 环境变量使用Environment Variables Configuration Provider. 如果一个自定义前缀被使用了,这个前缀会在configuration key-value pairs被加载时去掉。(例如, PREFIX_ with .AddEnvironmentVariables(prefix:”PREFIX_”)).
    • Command-line 参数使用command-line Configuration Provider

    3.Security

    采用下面的最佳实践:

    • 不要存储密码或者其他敏感数据在configuration provider code或者 plain text configuration files.
    • 不要在开发和测试环境使用production secrets
    • 在项目外,指定secrets,以便它们不会被意外提交到源代码仓库

    4.Hierarchical configuration data(分层的配置数据)

    在下面的JSON文件中,结构化分层的两个sections中存在四个key

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

    当文件被读取到配置中时,唯一的key被创建,来维护原始配置源中的分层数据结构。

    Sectionkey被使用冒号展开来维持原始结构:

    section0:key0

    section0:key1

    section1:key0

    section1:key1

    如上,每个值都可以被唯一的取到

    GetSectionGetChildren方法可以被用来分离配置数据中的sectionssectionchildren 。这些方法会在随后的GetSectionGetChildren,Exists描述。GetSection是在Microsoft.Extensions.Configuration包中,这个包是在Microsoft.AspNetCore.App metapackage.

    5.Conventions(习惯,约定)

    这里是一些习惯的约定。

    在应用启动时,配置源按照它们的configuration provider被指定的顺序来被读取

    Configuration providers实现了变化检测,Configuration providers可以重新加载配置,当一个基础的设置被改变时。例如,File Configuration ProviderAzure key Value Configuration Provider实现了变化检测。

    IConfiguration在应用的依赖注入(DI)容器中是可用的IConfiguration可以被注入到一个Razor Pages Pagemodel来包含一个配置的类。

    public class IndexModel : PageModel
    {
        private readonly IConfiguration _config;
    
        public IndexModel(IConfiguration config)
        {
            _config = config;
        }
    
        // The _config local variable is used to obtain configuration 
        // throughout the class.
    }

    Configuration providers不能使用DI,因为当它们(Configuration providers)host建立时,DI是不可用的

    Configuration keys采用下面的约定

    • Keys忽略大小写。例如ConnectionStringconnectionstring被认为是相同的键(keys)
    • If a value for the same key is set by the same or different configuration providers, the last value set on the key is the value used.(如果同一个key的值被不同的数据提供器设置,会默认使用后面设置的,按configuration providers指定的顺序)
    • 分层keys
      • Configuration API中,冒号:可以在所有平台起作用
      • 在环境变量中,冒号可能不能在所有平台起作用。双下划线(__)被所有平台支持并且转化为冒号
      • Azure Key Vault,分层的keys--(两个中杠)作为分割符,你必须提供代码来用冒号替换这两个中杠。当secrets被加载到应用的配置中时。
    • ConfigurationBinder支持绑定数组到对象,在配置keys中使用array 标识体。数组绑定会在Bind an array to class节描述。

    Configuratian values采用下面的约定

    • Values都是string
    • Null值不能被存储在配置中或者绑定到对象

    6.Providers

    下面列出了ASP.NET Core应用可用的configuration providers:

    Configuration sources(配置源)按照它们的configuration providersstartup中指定的顺序被顺序读取。

    典型的configuration providers的顺序:

    1. Files (appsettings.json, appsettings.{Environment}.json, {Environment}是应用当前的运行环境)
    2. Azure Key Vault
    3. User secrets (Secret Manager)(仅用在开发环境)
    4. Environment variables
    5. Command-line arguments

    这是一种通用的实践,把命令行配置源放到最后,使它可以重写其他配置源设置的配置。

    注意:后面的配置会覆盖前面的配置

    7.ConfigureAppConfiguration

    调用ConfigureAppConfiguration,当需要建立host指定除了被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.SetBasePath(Directory.GetCurrentDirectory());
                    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>();
    }

    二.configuration provider讲解

    8.Command-line Configuration Provider

    在运行时,CommandLineConfigurationProviders从command line argument key-value pairs中加载配置.

    要想启动command-line 配置,AddCommandLine扩展方法需要在ConfigurationBuilder实例中被调用

    AddCommandLine早已被CreateDefaultBuilder调用。如果你需要提供 app configuration 并且仍然可以用command-line arguments重写配置,在ConfigureAppConfiguration中,调用app的额外的providers,并且在最后调用AddCommandLine.

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }
    
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    // Call other providers here and call AddCommandLine last.
                    config.AddCommandLine(args);
                })
                .UseStartup<Startup>();
    }

    当直接创建一个WebHostBuilder时,调用UseConfiguration(另一种用法):

    var config = new ConfigurationBuilder()
        // Call additional providers here as needed.
        // Call AddCommandLine last to allow arguments to override other configuration.
        .AddCommandLine(args)
        .Build();
    
    var host = new WebHostBuilder()
        .UseConfiguration(config)
        .UseKestrel()
        .UseStartup<Startup>();

    Example

    示例应用功能利用静态方法CreateDefaultBuilder来建立host,它包含对AddCommandLine的调用.

    1. 在项目目录打开命令行
    2. 把命令行参数用到 dotnet run 命令,dotnet run CommandLineKey=CommandLineValue
    3. 在应用运行之后,打开浏览器到应用的 http://localhost:5000
    4. 观察输出(dotnet run)

    Arguments

    值必须是下面的形式.=后面的值可以为null(例如,CommandLineKey=)

    在同一个命令窗口中,不要混合使用=号和空格

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

    Switch mappings

     Switch mapping dictionary key rules:

    • Swithes必须以-或者- - 开头
    • Swith mappings不能包含重复的keys

    当建立host指定应用配置时,调用ConfigureAppConfiguration

    public class Program
    {
        public static readonly Dictionary<string, string> _switchMappings = 
            new Dictionary<string, string>
            {
                { "-CLKey1", "CommandLineKey1" },//把命令行中key为-CLKey1的键替换为key为CommandLineKey1
                { "-CLKey2", "CommandLineKey2" }
            };
    
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }
    
        // Do not pass the args to CreateDefaultBuilder
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder()
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    config.AddCommandLine(args, _switchMappings);
                })
                .UseStartup<Startup>();
    }

    switch mappings dictionary被创建后,包含下面的数据:

    如果启动应用时,switch-mapped keys被使用,configuration会在dictionary提供的key里接收到配置值。

    dotnet run -CLKey1=value1 -CLKey2=value2

    在运行之前的命令后,configuration包含了值,如下表:

    如上,可以看出Switch mappings的作用是:

     把命令行中输入的key替换为switch mapping中的key值。

    9.Environment Variables Configuration Provider

    要启用environment variables configuration,需要调用AddEnvironmentVariables扩展方法

    AddEnvironmentVariables用来加载以ASPNETCORE_开头的环境变量。

    当建立host指定应用配置时,调用ConfigureAppConfiguration :

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }
    
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    // Call additional providers here as needed.
                    // Call AddEnvironmentVariables last if you need to allow
                    // environment variables to override values from other 
                    // providers.
                    config.AddEnvironmentVariables(prefix: "PREFIX_");
                })
                .UseStartup<Startup>();
    }

    当直接创建WebHostBuilder,调用UseConfiguration:

    var config = new ConfigurationBuilder()
        .AddEnvironmentVariables()
        .Build();
    
    var host = new WebHostBuilder()
        .UseConfiguration(config)
        .UseKestrel()
        .UseStartup<Startup>();

    Example

    示例应用功能利用静态方法CreateDefaultBuilder来建立host,它包含对AddEnvironmentVariables的调用.

    1. 运行示例应用。浏览 http://localhost:5000
    2. 观察环境变量的输出。

    环境变量以下面的开头

    • ASPNETCORE_
    • urls
    • Logging
    • ENVIRONMENT
    • contentRoot
    • AllowedHosts
    • applicationName
    • CommandLine

    如果你希望在应用中暴露这些环境变量可用,在Pages/Index.cshtml.cs中改变FilteredConfiguration为下面:

    FilteredConfiguration = _config.AsEnumerable();

    Prefixes

    当你应用一个前缀到AddEnvironmentVariables方法,应用配置中的环境变量可以被过滤。例如,在前缀CUSTOM_上过滤环境变量,应用前缀到configuration provider:

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

    前缀会被分离,当配置key-values pairs被创建时。

    静态方法CreateDefaultBuilder会创建一个WebHostBuilder来建立应用主机。当WebHostBuilder被创建时,可以在环境变量中找到ASPNETCORE_为前缀的主机配置。

    (1).Connection string prefixes

    Configuration API(配置api)对于四个连接字符串环境变量有特殊的处理规则。如果没有前缀作用到AddEnvironmentVariables,带有下面前缀的环境变量会被加载到应用中

    当一个环境变量被发现,并且带有上面四个之一的前缀被加载到配置:

    • configuration key通过移除环境变量前缀来创建,并且增加一个configuration key section(ConnectionStrings)
    • 一个新的configuration key-value pair被创建了,它代表database connection provider(只有CUSTOMCONNSTR_,which has no stated provider).

    10.File Configuration Provider

    FileConfigurationProvider是从文件系统中加载配置的基础类。下面的configuration providers是作用特定的文件类型:

    • INI Configuration Provider
    • JSON Configuration Provider
    • XML Configuration Provider

    INI Configuration Provider

    IniConfigurationProviderINI文件中加载配置。

    要启用INI 文件配置,在ConfigurationBuilder实例中调用AddIniFile扩展方法

    重写一些指定配置选项

    • 文件是否是可选的
    • 如果文件改变,配置是否重新加载
    • IFileProvider用于获取文件

    调用ConfigureAppConfiguration,当建立host指定应用配置时:

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }
    
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    config.SetBasePath(Directory.GetCurrentDirectory());
                    config.AddIniFile(
                        "config.ini", optional: true, reloadOnChange: true);
                })
                .UseStartup<Startup>();
    }

    基础路径(base path)是通过SetBasePath设置。SetBasePath是在Microsoft.Extensions.Configuration.FileExtension包中,这个包是在Microsoft.AspNetCore.App metapackage.

    当直接创建一个WebHostBuilder,调用UseConfiguration

    var config = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddIniFile("config.ini", optional: true, reloadOnChange: true)
        .Build();
    
    var host = new WebHostBuilder()
        .UseConfiguration(config)
        .UseKestrel()
        .UseStartup<Startup>();

    一个INI configuration file示例:

    [section0]
    key0=value
    key1=value
    
    [section1]
    subsection:key=value
    
    [section2:subsection0]
    key=value
    
    [section2:subsection1]
    key=value

    上面的配置文件加载下面的keyvalue:

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

    JSON Configuration Provider

    JsonConfigurationProviderJSON文件中加载配置.

    要启用JSON文件配置,在ConfigurationBuilder实例上,调用AddJsonFile扩展方法。

    重写一些指定配置选项

    • 文件是否是可选的
    • 如果文件改变,配置是否重新加载
    • IFileProvider用于获取文件

    AddJsonFile会自动调用两次,当你用CreateDefaultBuilder初始化一个WebHostBuilder时。这个方法被调用加载配置,从下面的:

    • appsettings.json - 这个文件被首先读取。这个文件的环境版本可以重写appsettings.json文件提供的值。
    • appsettings.{Environment}.json - 这个文件的环境版本(environment version)依据于IHostingEnvironment.EnvironmentName被加载

    调用ConfiureAppConfiguration当建立host来指定应用配置,通过其他文件而不是通过appsettings.jsonappsettings.{Environment}.json文件

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }
    
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    config.SetBasePath(Directory.GetCurrentDirectory());
                    config.AddJsonFile(
                        "config.json", optional: true, reloadOnChange: true);
                })
                .UseStartup<Startup>();
    }

    当直接创建WebHostBuilder,调用UseConfiguration:

    var config = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("config.json", optional: true, reloadOnChange: true)
        .Build();
    
    var host = new WebHostBuilder()
        .UseConfiguration(config)
        .UseKestrel()
        .UseStartup<Startup>();

    Example

    示例应用利用静态方法CreateDefaultBuilder来建立host,它包含两次对AddJsonFile的调用。配置从appsettings.jsonappsettings.{Environment}.json文件中加载

    1. 运行示例应用。浏览 http://localhost:5000
    2. 观察配置中的输出

    XML Configuration Provider

    XmlConfigurationProviderXML文件中加载配置。

    要启用XML文件配置,在ConfigurationBuilder实例上调用AddXmlFile扩展方法。

    配置文件的根节点被忽略了,当配置key-value pairs被创建了。不要在文件中指定一个Document Type Definition(DTD)或者命名空间。

    调用ConfigureAppConfiguration,当建立host来指定应用的配置时:

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }
    
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    config.SetBasePath(Directory.GetCurrentDirectory());
                    config.AddXmlFile(
                        "config.xml", optional: true, reloadOnChange: true);
                })
                .UseStartup<Startup>();
    }

    当直接创建WebHostBuilder,调用UseConfiguration:

    var config = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddXmlFile("config.xml", optional: true, reloadOnChange: true)
        .Build();
    
    var host = new WebHostBuilder()
        .UseConfiguration(config)
        .UseKestrel()
        .UseStartup<Startup>();

    (1).XML配置文件可以使用distinct元素名称对于repeating sections:

    <?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>

    前面的配置文件在家下面的keyvalue:

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

    (2).还可以如下,用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>

    之前的配合文件加载下面的keyvalue

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

    (3).属性也可以用于值上

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

    之前的配置文件加载下面的keyvalue:

    • key:attribute
    • section:key:attribute

    11.Key-per-file Configuration Provider

    KeyPerFileConfigurationProvider使用一个目录文件作为configuration key-value pairs.其中key是文件名value包含文件内容Key-per-file Configuration Provider用于Docker hosting 场景。

    要启用key-per-file configuration, ConfigurationBuilder实例上,调用AddKeyPerFile扩展方法。文件的目录路径(directoryPath)必须是绝对路径

    Overloads permit specifying:

    • Action<KeyPerFileConfigurationSource>委托 ,来配置source
    • 目录是否是可选的,和目录路径

    在文件名字中,双下划线(__)用作一个configuration key 分隔符。例如,文件名Logging__LogLevel__System产生configuration key : Logging:logLevel:System

    调用ConfigureAppConfiguration,当建立host来指定应用的配置时:

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }
    
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    config.SetBasePath(Directory.GetCurrentDirectory());
                    var path = Path.Combine(
                        Directory.GetCurrentDirectory(), "path/to/files");
                    config.AddKeyPerFile(directoryPath: path, optional: true);
                })
                .UseStartup<Startup>();
    }

    当直接创建WebHostBuilder时,调用UseConfiguration:

    var path = Path.Combine(Directory.GetCurrentDirectory(), "path/to/files");
    var config = new ConfigurationBuilder()
        .AddKeyPerFile(directoryPath: path, optional: true)
        .Build();
    
    var host = new WebHostBuilder()
        .UseConfiguration(config)
        .UseKestrel()
        .UseStartup<Startup>();

    12.Memory Configuration Provider

    MemoryConfigurationProvider使用内存集合作为配置key-value pairs.

    要使用in-memory collection configuration,ConfigurationBuilder实例上,调用AddInMemoryCollection扩展方法。

    The configuration provider可以使用IEnumerable<KeyValuePair<String,String>>来初始化。

    当建立host来指定应用配置时,调用ConfigureAppConfiguration:

    public class Program
    {
        public static readonly Dictionary<string, string> _dict = 
            new Dictionary<string, string>
            {
                {"MemoryCollectionKey1", "value1"},
                {"MemoryCollectionKey2", "value2"}
            };
    
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }
    
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    config.AddInMemoryCollection(_dict);
                })
                .UseStartup<Startup>();
    }

    当直接创建WebHostBuilder时,调用UseConfiguration:

    var dict = new Dictionary<string, string>
        {
            {"MemoryCollectionKey1", "value1"},
            {"MemoryCollectionKey2", "value2"}
        };
    
    var config = new ConfigurationBuilder()
        .AddInMemoryCollection(dict)
        .Build();
    
    var host = new WebHostBuilder()
        .UseConfiguration(config)
        .UseKestrel()
        .UseStartup<Startup>();

    三.其他

    13.GetValue

    ConfigurationBinder.GetValue<T> 从配置文件中用特定的key提出value,并且转化为特定类型。如果这个key没找到,可以提供默认值。

    下面的例子:

    • keyNumberKey,从配置中提取string value.如果NumberKey没有在配置中找到,默认的value99会被使用
    • 把这个value转化为int类型
    • 通过page存储值
    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);
        }
    }

    14.GetSection, GetChildren, and Exists

    {
      "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用特定的subsection key提取一个configuration subsection.

    要返回一个包含在section1中的key-value pairsIConfigurationSection,调用GetSection并且应用section name:

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

    其中configSection没有value,只有一个keypath.

    相似的,要包含keysection2:subsection0value,调用GetSection并且应用section path:

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

    GetSection不会返回null。 如果没有匹配的section,一个空的IConfigurationSection会被返回。

     GetChildren

    调用在section2上的IConfiguration.GetChildren包含:

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

    Exists

    ConfigurationExtensions.Exists来确定configuration section是否存在:

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

    给出的例子中的数据,sectionExistsfalse,因为section2:subsection2这个section不存在。

    15.Bind to a class

    配置可以被绑定到类中。

    示例包含一个Startshipmodel(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; }
    }

    Starship.json文件中starshipsection节创建了配置,当示例应用使用JSON Configuration Provider加载配置时。

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

    下面的配置被创建了:

    示例应用利用keystarship来调用GetSectionStarship key-value pairs被分离。在绑定实例值后:

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

    16.Bind to an object graph

    示例绑定一个TvShowmodel它包含MetadataActors类:

    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>();

    17.Bind an array to a c lass

    Bind还支持绑定数组.

    In-memory array processing

    考虑下面配置中的keysvalues:

     

    示例应用中的keysvalues被使用Memory Configuration Provider被加载:

    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.SetBasePath(Directory.GetCurrentDirectory());
                    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的值。Configuration binder不能绑定null 值或者创建null entries在绑定对象中。

    在示例中,一个类用来绑定配置数据:

    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的实例,接收到配置中的数组数据:

    在绑定对象中,索引为3有的是array:4的值。

    要处理这样的情况,可以这样,使用一个额外的JOSN Configuration Provider处理丢失的key-value pair, ArrayExample.Entries匹配完整的配置数组:

    missing_value.json:

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

    ConfigureAppConfiguration中:

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

    下面的值会被加载到配置中:

    如果ArrayExample类的实例是在JSON Configuration Provider包含索引3后被绑定ArrayExample.Entries数组会包含这个值

    JSON array processing

    如果JSON文件包含一个数组,配置keys被创建为数组的索引。下面的配置文件中,subsection是一个数组:

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

    JSON Configuration Provider读取配置数据到下面所列:

    在示例应用中,下面的类用来绑定配置数据

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

    在绑定后,JsonArrayExample.Key有值valueAsubsection的值存储在Subsection属性的数组中

    四.对于自定义configuration provider

    18.Custom configuration provider

    示例应用说明怎么创建一个基础的configuration provider,它可以使用Entity Framework从数据库读取数据

    provider有下面特征

    • EF in-memory database是用于证明目的。
    • startup中,provider读取数据库表到配置中.
    • Reload-on-change没有实现,所以在应用启动后更新数据库对于应用的配置没有作用。

    定义个EFConfigurationValue实体来存储数据库中的配置数据

    Models/EFConfigurationValues.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);
        }
    }

    创建一个自定义的configuration provider通过继承ConfigurationProvider.这个configuration provider初始化数据库,当它是空的时

    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>
                {
                    { "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/EntityFrameworkExtension.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.SetBasePath(Directory.GetCurrentDirectory());
                    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>();
    }

     

    19.Access configuration during startup

    Startup.ConfigureServices中注入IConfigurationStartup构造函数中来取得配置数据。要再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"];
        }
    }

    20.Access configuration in a Razor Pages page or MVC view

    Razor Pages page或者MVC view中取得configuration settings.增加一个using指令为Microsoft.Extensions.Configuration 命名空间并且把IConfiguration注入到page或者view

    Razor Pages page:

    @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 view中:

    @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>

    参考网址:

    https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.2

  • 相关阅读:
    Cornerstone-忽略(隐藏)文件
    ios开发xcode8+ 无需开发者账号,app打包ipa
    ssh-ajax登陆action返回字符串
    手动编译包含两个import自写类的java类。
    关闭IO资源
    java聊天室二(客户端)
    java聊天室一(服务器)
    文件IO常用操作
    Hive启动时的棘手问题的处理
    对于java反射的理解
  • 原文地址:https://www.cnblogs.com/Vincent-yuan/p/11186196.html
Copyright © 2020-2023  润新知