在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被創建,來維護原始配置源中的分層數據結構。
Section和key被使用冒號展開來維持原始結構:
section0:key0
section0:key1
section1:key0
section1:key1
如上,每個值都可以被唯一的取到。
GetSection和GetChildren方法可以被用來分離配置數據中的sections和section的children 。這些方法會在隨后的GetSection,GetChildren,和Exists描述。GetSection是在Microsoft.Extensions.Configuration包中,這個包是在Microsoft.AspNetCore.App metapackage.
5.Conventions(習慣,約定)
這里是一些習慣的約定。
在應用啟動時,配置源按照它們的configuration provider被指定的順序來被讀取。
Configuration providers實現了變化檢測,Configuration providers可以重新加載配置,當一個基礎的設置被改變時。例如,File Configuration Provider和Azure 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忽略大小寫。例如ConnectionString和connectionstring被認為是相同的鍵(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 providers在startup中指定的順序被順序讀取。
典型的configuration providers的順序:
- Files (appsettings.json, appsettings.{Environment}.json, {Environment}是應用當前的運行環境)
- Azure Key Vault
- User secrets (Secret Manager)(僅用在開發環境)
- Environment variables
- 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的調用.
- 在項目目錄打開命令行
- 把命令行參數用到 dotnet run 命令,dotnet run CommandLineKey=CommandLineValue
- 在應用運行之后,打開瀏覽器到應用的 http://localhost:5000
- 觀察輸出(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的調用.
- 運行示例應用。瀏覽 http://localhost:5000
- 觀察環境變量的輸出。
環境變量以下面的開頭:
- 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
IniConfigurationProvider從INI文件中加載配置。
要啟用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
上面的配置文件加載下面的key和value:
- section0:key0
- section0:key1
- section1:subsection:key
- section2:subsection0:key
- section2:subsection1:key
JSON Configuration Provider
JsonConfigurationProvider從JSON文件中加載配置.
要啟用JSON文件配置,在ConfigurationBuilder實例上,調用AddJsonFile擴展方法。
重寫一些指定配置選項:
- 文件是否是可選的
- 如果文件改變,配置是否重新加載
- IFileProvider用於獲取文件
AddJsonFile會自動調用兩次,當你用CreateDefaultBuilder初始化一個WebHostBuilder時。這個方法被調用加載配置,從下面的:
- appsettings.json - 這個文件被首先讀取。這個文件的環境版本可以重寫appsettings.json文件提供的值。
- appsettings.{Environment}.json - 這個文件的環境版本(environment version)依據於IHostingEnvironment.EnvironmentName被加載
調用ConfiureAppConfiguration,當建立host來指定應用配置,通過其他文件而不是通過appsettings.json和appsettings.{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.json和appsettings.{Environment}.json文件中加載
- 運行示例應用。瀏覽 http://localhost:5000
- 觀察配置中的輸出
XML Configuration Provider
XmlConfigurationProvider從XML文件中加載配置。
要啟用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>
前面的配置文件在家下面的key和value:
- 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>
之前的配合文件加載下面的key和value:
- 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>
之前的配置文件加載下面的key和value:
- 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沒找到,可以提供默認值。
下面的例子:
- 用key為NumberKey,從配置中提取string value.如果NumberKey沒有在配置中找到,默認的value值99會被使用
- 把這個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 pairs的IConfigurationSection,調用GetSection並且應用section name:
var configSection = _config.GetSection("section1");
其中configSection沒有value,只有一個key和path.
相似的,要包含key為section2:subsection0的value,調用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();
給出的例子中的數據,sectionExists是false,因為section2:subsection2這個section不存在。
15.Bind to a class
配置可以被綁定到類中。
示例包含一個Startship的model(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文件中starship的section節創建了配置,當示例應用使用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" }
下面的配置被創建了:
示例應用利用key為starship來調用GetSection。Starship key-value pairs被分離。在綁定實例值后:
var starship = new Starship(); _config.GetSection("starship").Bind(starship); Starship = starship;
16.Bind to an object graph
示例綁定一個TvShow的model,它包含Metadata和Actors類:
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
考慮下面配置中的keys和values:
示例應用中的keys和values被使用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有值valueA,subsection的值存儲在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中注入IConfiguration到Startup構造函數中來取得配置數據。要再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