asp.net core 系列之Configuration

ASP.NET Core中的App configuration 是經過configuration providers基於key-value對創建的。Configuration providers讀取配置文件到key-value,從多種配置源中:html

  • 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(對比)json

在應用配置和啓動以前,host被配置和launched(發動,開展)Host 負責應用的startup和生命週期管理。應用和主機都是用這個主題描述的configuration providers來配置。主機配置的key-values對成爲應用全局配置的一部分。api

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).應用配置是被下面這些提供的:app

  • 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.Securityide

採用下面的最佳實踐:函數

  • 不要存儲密碼或者其餘敏感數據在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

相關文章
相關標籤/搜索