咱們以前寫的配置都是放置在配置文件Web.config或者app.config中,.net core提供了全新的配置方式,能夠直接寫在內存中或者寫在文件中。html
.Net Core的配置API主要體如今3個類中Configuration、ConfigurationBuilder、ConfigurationProvider中。json
配置文件其實就是一個鍵值對。Configuration以樹形結構描述了這些鍵值對之間的關係。咱們的配置文件好比project.json是怎麼轉換成Configuration樹形結構的呢?app
Microsoft.Extensions.Options這個命名空間下的類提供了文件向Configuration的轉換。ide
1、配置文件分爲3種結構ui
1. 邏輯結構:就是咱們看到的結構,樹形結構。this
2. 原始結構:就是文件自己的結構,好比xml、json等等。spa
3. 物理結構:介於二者之間的結構,鍵值對。.net
配置組件的最終目的就是把原始結構轉化成邏輯結構,在具體轉換過程當中,先找到對應的ConfigurationProvider轉化爲物理結構數據字典,而後再由ConfigurationBuilder轉化爲邏輯結構Configuration對象。code
2、Configurationxml
Configuration對象泛指繼承自接口IConfiguration的對象。這個接口以下:
namespace Microsoft.Extensions.Configuration { using Microsoft.Extensions.Primitives; using System; using System.Collections.Generic; using System.Reflection; public interface IConfiguration { IEnumerable<IConfigurationSection> GetChildren(); IChangeToken GetReloadToken(); IConfigurationSection GetSection(string key); string this[string key] { get; set; } } }
這個接口GetChildren表示全部的ConfigurationSection對象;GetSection根據key值獲得ConfigurationSection對象。
繼承自這個接口的對象分別是ConfigurationRoot和ConfigurationSection,分別表示配置的根節點和葉子節點。
ConfigurationRoot還繼承自接口IConfigurationRoot接口,代碼以下:
namespace Microsoft.Extensions.Configuration { using System; public interface IConfigurationRoot : IConfiguration { void Reload(); } }
這個接口只有一個方法Reload從新加載,當調用這個方法的時候,在這棵樹下的全部的節點都會從新加載。
ConfigurationSection還繼承自IConfigurationSection,代碼以下:
namespace Microsoft.Extensions.Configuration { using System; public interface IConfigurationSection : IConfiguration { string Key { get; } string Path { get; } string Value { get; set; } } }
Key表示父節點的名稱;Path表示當前節點的路徑,用「:」隔開;Value只有在葉子節點纔有值,非葉子節點返回Null。
3、ConfigurationProvider
ConfigurationProvider對象泛指實現了接口IConfigurationProvider的對象。
namespace Microsoft.Extensions.Configuration { using Microsoft.Extensions.Primitives; using System; using System.Collections.Generic; using System.Runtime.InteropServices; public interface IConfigurationProvider { IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath); IChangeToken GetReloadToken(); void Load(); void Set(string key, string value); bool TryGet(string key, out string value); } }
而繼承自這個接口的是一個抽象類ConfigurationProvider,代碼以下:
public abstract class ConfigurationProvider : IConfigurationProvider { // Fields private ConfigurationReloadToken _reloadToken; // Methods protected ConfigurationProvider(); public virtual IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath); public IChangeToken GetReloadToken(); public virtual void Load(); protected void OnReload(); private static string Segment(string key, int prefixLength); public virtual void Set(string key, string value); public virtual bool TryGet(string key, out string value); // Properties protected IDictionary<string, string> Data { get; set; } }
由於這個類的最終目的就是轉化爲數據字典,因此,這個類的方法大部分都是針對數據字典,方法的參數中都有key值。
不一樣的數據源都是繼承自這個抽象類,重寫本身的方法。
Load方法從數據源加載數據,針對不一樣的數據源子類能夠重寫;TryGet根據key值獲取數據值;Set方法設置數據值,由於這個類的主要功能是從數據源讀取數據轉化爲數據字典,因此Set的值只保存在內存中。
4、ConfigurationBuilder
泛指實現了接口IConfigurationBuilder的對象。他的做用就是根據ConfigurationProvider提供的數據字典,把數據字典轉化爲ConfigurationRoot對象。接口以下:
namespace Microsoft.Extensions.Configuration { using System.Collections.Generic; public interface IConfigurationBuilder { IConfigurationBuilder Add(IConfigurationSource source); IConfigurationRoot Build(); Dictionary<string, object> Properties { get; } IEnumerable<IConfigurationSource> Sources { get; } } }
主要經過Build方法實現把數據字典轉化爲ConfigurationRoot。
不管是ConfigurationRoot仍是ConfigurationSection自己都沒有封裝任何形式的對配置的讀取操做,全部的讀取操做都是在ConfigurationProvider對象中。
在ConfigurationRoot和ConfigurationSection組成的樹形結構中,並無在代碼中直接保存這種結構,而是每一個ConfigurationSection中都有一個ConfigurationRoot對象,直接是對根節點的引用。而只有根節點中有對ConfigurationProvider的調用。也就是在每一個葉子節點中都有一個對於根節點的引用。這樣當咱們想要獲取某個節點的具體值時,先找到根節點,再經過根節點找到ConfigurationProvider,經過ConfigurationProvider對象獲取配置值。
還有一個對象ConfigurationPath,主要封裝對樹層級結構的計算,代碼以下:
namespace Microsoft.Extensions.Configuration { using System; using System.Collections.Generic; public static class ConfigurationPath { public static readonly string KeyDelimiter = ":"; public static string Combine(IEnumerable<string> pathSegments) { if (pathSegments == null) { throw new ArgumentNullException("pathSegments"); } return string.Join(KeyDelimiter, pathSegments); } public static string Combine(params string[] pathSegments) { if (pathSegments == null) { throw new ArgumentNullException("pathSegments"); } return string.Join(KeyDelimiter, pathSegments); } public static string GetParentPath(string path) { if (!string.IsNullOrEmpty(path)) { int length = path.LastIndexOf(KeyDelimiter, (StringComparison) StringComparison.OrdinalIgnoreCase); if (length != -1) { return path.Substring(0, length); } } return null; } public static string GetSectionKey(string path) { if (!string.IsNullOrEmpty(path)) { int num = path.LastIndexOf(KeyDelimiter, (StringComparison) StringComparison.OrdinalIgnoreCase); if (num != -1) { return path.Substring(num + 1); } } return path; } } }
Combine方法實現把路徑鏈接成一個完整的路徑。
以上對象之間的關係圖以下:
綜上,配置模塊的最終目的是要把原始的配置文件好比:json、xml轉換爲一個ConfigurationRoot對象,這個對象是一個樹形結構,下邊是ConfigurationSection對象。當咱們要獲取某個配置時,經過ConfigurationRoot的ConfigurationProvider獲取,每一個ConfigurationSection都有一個對於根節點的引用。
後記:當須要讀取一個配置文件的時候,調用ConfigurationBuilder的build方法把文件內容轉換爲ConfigurationRoot對象,在這個方法執行過程當中,會調用根據配置文件的不一樣調用相關的ConfigurationProvider ,而後調用ConfigurationProvider的Load方法,把配置文件轉換成數據字典;而後再回到ConfigurationBuilder中把數據字典轉化爲ConfigurationRoot。
參考連接:http://www.cnblogs.com/artech/p/asp-net-core-config-01.html