這篇文章主要介紹了ASP.NET Core配置教程的第一篇讀取配置信息,感興趣的小伙伴們可以參考一下
#提到“配置”二字,我想絕大部分.NET開發人員腦海中會立刻浮現出兩個特殊文件的身影,那就是我們再熟悉不過的app.config和web.config,多年來我們已經習慣了將結構化的配置資訊定義在這兩個文件之中。到了.NET Core的時候,很多我們習以為常的東西都改變了,其中也包含定義配置的方式。總的來說,新的配置系統顯得更加輕量級,並且具有更好的擴展性,其最大的特點就是支援多樣化的資料來源。我們可以採用記憶體的變數作為配置的資料來源,也可以直接配置定義在持久的檔案甚至資料庫中。
由於很多人都不曾接觸過這個採用全新設計的配置系統,為了讓大家對此有一個感官的認識,我們先從編程的角度對它作一個初體驗。針對配置的API涉及三個物件,它們分別是Configuration、ConfigurationBuilder和ConfigurationProvider,配置模型中具有對應的介面來表示它們。這三個物件之間的關係很清晰,Configuration物件承載著在程式設計過程中使用的配置訊息,ConfigurationProvider則是配置訊息原始資料來源的提供者,兩者之間溝通由ConfigurationBuilder來完成,它利用ConfigurationProvider提取來源資料將其轉換為Configuration物件。
一、以鍵-值對的形式讀取配置
雖然在大部分情況下的配置資訊從整體來說都具有一個結構化的層次關係,但是「原子」配置項都以最簡單的「鍵-值對」的形式來體現,並且鍵和值都是字串,接下來我們會透過一個簡單的實例來示範如何以鍵值對的形式來讀取配置。我們建立一個針對ASP.NET Core的控制台應用,並在project.json中按照如下的方式添加針對「Microsoft.Extensions.Configuration」這個NuGet套件的依賴,配置模型就實現在這個包中。
{ ... "dependencies": { "Microsoft.Extensions.Configuration": "1.0.0-rc1-final" }, }
假設我們的應用程式需要透過配置來設定日期/時間的顯示格式,為此我們定義瞭如下一個DateTimeFormatSettings類,它的四個屬性體現了DateTime物件的四種顯示格式(分別為長日期/時間和短日期/時間)。
public class DateTimeFormatSettings { public string LongDatePattern { get; set; } public string LongTimePattern { get; set; } public string ShortDatePattern { get; set; } public string ShortTimePattern { get; set; } //其他成员 }
我們希望透過配置的形式來控制由DateTimeFormatSettings的四個屬性所體現的日期/時間顯示格式,所以我們為它定義了一個建構子。如下面的程式碼片段所示,該建構函式具有一個IConfiguration介面類型的參數,它正式承載相關配置資訊的Configuration物件。我們呼叫Configuration物件的索引並指定對應配置項的Key來得到其Value。
public class DateTimeFormatSettings { //其他成员 public DateTimeFormatSettings (IConfiguration configuration) { this.LongDatePattern = configuration["LongDatePattern"]; this.LongTimePattern = configuration["LongTimePattern"]; this.ShortDatePattern = configuration["ShortDatePattern"]; this.ShortTimePattern = configuration["ShortTimePattern"]; } }
要建立一個體現目前配置的DateTimeFormatSettings對象,我們必須向得到這個承載相關配置資訊的Configuration對象。正如我們上面所說,Configuration對像是由ConfigurationBuilder創建的,而原始的配置資訊是透過對應的ConfigurationProvider來讀取的,所以創建一個Configuration對象的正確編程方式是先創建一個ConfigurationBuilder對象,然後為此添加一個或多個ConfigurationProvider對象,最後利用ConfigurationBuilder來建立我們需要的Configuration物件。
依照上述的程式設計模式,我們在一個控制台應用中編寫如下的程式。我們建立了一個類型為ConfigurationBuilder的對象,呼叫其Add方法所新增的ConfigurationProvider是一個類型為MemoryConfigurationProvider的對象。顧名思義,MemoryConfigurationProvider利用記憶體中的物件來提供原始的配置訊息,具體來說這些原始的配置資訊保存在一個元素類型為KeyValuePair708d620c35cc3f2d1dd0b997d136c07a的集合之中。我們最終呼叫ConfigurationBuilder的Build方法取得用於建立DateTimeFormatSettings物件所需的Configuration。
public class Program { public static void Main(string[] args) { Dictionary<string, string> source = new Dictionary<string, string> { ["LongDatePattern"] = "dddd, MMMM d, yyyy", ["LongTimePattern"] = "h:mm:ss tt", ["ShortDatePattern"] = "M/d/yyyy", ["ShortTimePattern"] = "h:mm tt" }; IConfiguration configuration = new ConfigurationBuilder() .Add(new MemoryConfigurationProvider(source)) .Build(); DateTimeFormatSettings settings = new DateTimeFormatSettings(configuration); Console.WriteLine("{0,-16}: {1}", "LongDatePattern", settings.LongDatePattern); Console.WriteLine("{0,-16}: {1}", "LongTimePattern", settings.LongTimePattern); Console.WriteLine("{0,-16}: {1}", "ShortDatePattern", settings.ShortDatePattern); Console.WriteLine("{0,-16}: {1}", "ShortTimePattern", settings.ShortTimePattern); } }
为了验证根据配置创建的DateTimeFormatSettings对象与配置原始数据之间的关系,我们将它的四个属性输出于控制台上。当这个程序执行之后将在控制台上产生如下所示的输出,可以看出它正是我们提供的配置的真实反映。
LongDatePattern : dddd, MMMM d, yyyy
LongTimePattern : h:mm:ss tt
ShortDatePattern: M/d/yyyy
ShortTimePattern: h:mm tt
二、 读取结构化的配置
真实项目中涉及的配置大都具有一个结构化的层次结构,所以在配置模型中的Configuration对象同样具有这样的结构。结构化的配置具有一个树形层次结构,而一个Configuration对象表示的是组成这棵配置树的某个节点,这棵配置树则可以通过作为根节点的Configuration对象来体现。体现为键值对的原子配置项一般至存在于作为叶子节点的Configuration对象中,非叶子节点的Configuration包含一组子节点,而每个子节点同样是一个Configuration对象。
接下来我们同样以实例的方式来演示如何定义并读取具有层次化结构的配置。我们依然沿用上一节的应用场景,现在我们不仅仅需要设置日期/时间的格式,还需要设置其他数据类型的格式,比如表示货币的Decimal类型。为此我们定义了如下一个CurrencyDecimalFormatSettings类,它的属性Digits和Symbol分别表示小数位数和货币符号,一个CurrencyDecimalFormatSettings对象依然是利用一个表示配置的Configuration对象来创建的。
{ public int Digits { get; set; } public string Symbol { get; set; } public CurrencyDecimalFormatSettings(IConfiguration configuration) { this.Digits = int.Parse(configuration["Digits"]); this.Symbol = configuration["Symbol"]; } }
我们定义了另一个名为FormatSettings的类型来表示针对不同数据类型的格式设置。如下面的代码片段所示,它的两个属性DateTime和CurrencyDecimal分别表示针对日期/时间和货币数字的格式设置。FormatSettings依然具有一个参数类型为IConfiguration接口的构造函数,它的两个属性均在此构造函数中被初始化。值得注意的是初始化这两个属性采用的是当前Configuration的“子配置节”,通过指定配置节名称调用GetSection方法获得。
public class FormatSettings { public DateTimeFormatSettings DateTime { get; set; } public CurrencyDecimalFormatSettings CurrencyDecimal { get; set; } public FormatSettings(IConfiguration configuration) { this.DateTime = new DateTimeFormatSettings(configuration.GetSection("DateTime")); this.CurrencyDecimal = new CurrencyDecimalFormatSettings(configuration.GetSection("CurrencyDecimal")); } }
在我们上面演示的实例中,我们通过以一个MemoryConfigurationProvider对象来提供原始的配置信息。由于承载原始配置信息的是一个元素类型为KeyValuePair708d620c35cc3f2d1dd0b997d136c07a的集合,所以原始配置在物理存储上并不具有树形化的层次结构,那么它如何能够最终提供一个结构化的Configuration对象呢?其实很简单,虽然MemoryConfigurationProvider对象只能将配置信息存储为简单的“数据字典”,但是如果将Configuration对象在配置树中体现的路径作为Key,这个数据字典在逻辑上实际上就具有了一棵树的结构。实际上MemoryConfigurationProvider就是这么做的,这体现在我们如下所示的程序之中。
class Program { static void Main(string[] args) { Dictionary<string, string> source = new Dictionary<string, string> { ["Format:DateTime:LongDatePattern"] = "dddd, MMMM d, yyyy", ["Format:DateTime:LongTimePattern"] = "h:mm:ss tt", ["Format:DateTime:ShortDatePattern"] = "M/d/yyyy", ["Format:DateTime:ShortTimePattern"] = "h:mm tt", ["Format:CurrencyDecimal:Digits"] = "2", ["Format:CurrencyDecimal:Symbol"] = "$", }; IConfiguration configuration = new ConfigurationBuilder() .Add(new MemoryConfigurationProvider(source)) .Build(); FormatSettings settings = new FormatSettings(configuration.GetSection("Format")); Console.WriteLine("DateTime:"); Console.WriteLine("\t{0,-16}: {1}", "LongDatePattern", settings.DateTime.LongDatePattern); Console.WriteLine("\t{0,-16}: {1}", "LongTimePattern", settings.DateTime.LongTimePattern); Console.WriteLine("\t{0,-16}: {1}", "ShortDatePattern", settings.DateTime.ShortDatePattern); Console.WriteLine("\t{0,-16}: {1}\n", "ShortTimePattern", settings.DateTime.ShortTimePattern); Console.WriteLine("CurrencyDecimal:"); Console.WriteLine("\t{0,-16}: {1}", "Digits", settings.CurrencyDecimal.Digits); Console.WriteLine("\t{0,-16}: {1}", "Symbol", settings.CurrencyDecimal.Symbol); } }
如上面的代码片段所示,创建MemoryConfigurationProvider对象采用的字典对象包含6个基本的配置项,为了让它们在逻辑上具有一个树形化层次结构,所以的Key实际上体现了每个配置项所在配置节在配置树中的路径,路径采用冒号(“:”)进行分割。改程序执行之后会在控制台上呈现如下所示的输出结果。
DateTime: LongDatePattern : dddd, MMMM d, yyyy LongTimePattern : h:mm:ss tt ShortDatePattern: M/d/yyyy ShortTimePattern: h:mm tt CurrencyDecimal: Digits : 2 Symbol : $
三、将结构化配置直接绑定为对象
在真正的项目开发过程中,我们都不会直接使用直接读取的配置,而都倾向于像我们演示的两个实例一样通过创建相应的类型(比如DateTimeFormatSettings、CurrencyDecimalSettings和FormatSettings)来定义一组相关的配置选项(Option),我们将定义配置选项(Option)的这些类型称为Option类型。在上面演示的实例中,为了创建这些封装配置的对象,我们都是采用手工读取配置的形式,如果定义的配置项太多的话,逐条读取配置项其实是一项非常繁琐的工作。
对于一个对象来说,如果我们将它的属性视为它的子节点,一个对象同样具有类似于Configuration对象的树形层次化结构。如果我们根据某个Option类型的结构来定义配置,或者反过来根据配置的结构来定义这个Option类型,那么Option类型的属性成员将与某个配置节具有一一对应的关系,那么原则上我们可以自动将配置信息绑定为一个具体的Option对象。
ASP.NET Core针对配置的Option模型(OptionModel)帮助我们实现了从配置到Option对象之间的绑定,接下来我们就对此做一个简单的演示。Option模型实现在“Microsoft.Extensions.OptionModel”这个NuGet包中,除此之外,我们需要采用依赖注入的方式来使用Option模型,所以我们需要按照如下的方式为应用添加针对相应的依赖。
{ ... "dependencies": { "Microsoft.Extensions.OptionsModel" : "1.0.0-rc1-final", "Microsoft.Extensions.DependencyInjection" : "1.0.0-rc1-final" }, }
借助于Option模型的自动绑定机制,我们无需再手工地读取配置信息,所以我们将FormatSettings、DateTimeFormatSettings和CurrencyDecimalSettings的构造函数删除,只保留其属性成员。在作为程序入口的Main方法中,我们采用如下的方式创建这个表示格式设置的FormatSettings对象。
class Program { static void Main(string[] args) { Dictionary<string, string> source = new Dictionary<string, string> { ["Format:DateTime:LongDatePattern"] = "dddd, MMMM d, yyyy", ["Format:DateTime:LongTimePattern"] = "h:mm:ss tt", ["Format:DateTime:ShortDatePattern"] = "M/d/yyyy", ["Format:DateTime:ShortTimePattern"] = "h:mm tt", ["Format:CurrencyDecimal:Digits"] = "2", ["Format:CurrencyDecimal:Symbol"] = "$", }; IConfiguration configuration = new ConfigurationBuilder() .Add(new MemoryConfigurationProvider(source)) .Build() .GetSection("Format")); IOptions<FormatSettings> optionsAccessor = new ServiceCollection() .AddOptions() .Configure<FormatSettings>(configuration) .BuildServiceProvider() .GetService<IOptions<FormatSettings>>(); FormatSettings settings = optionsAccessor.Value; Console.WriteLine("DateTime:"); Console.WriteLine("\t{0,-16}: {1}", "LongDatePattern",settings.DateTime.LongDatePattern); Console.WriteLine("\t{0,-16}: {1}", "LongTimePattern",settings.DateTime.LongTimePattern); Console.WriteLine("\t{0,-16}: {1}", "ShortDatePattern",settings.DateTime.ShortDatePattern); Console.WriteLine("\t{0,-16}: {1}\n", "ShortTimePattern",settings.DateTime.ShortTimePattern); Console.WriteLine("CurrencyDecimal:"); Console.WriteLine("\t{0,-16}: {1}", "Digits",settings.CurrencyDecimal.Digits); Console.WriteLine("\t{0,-16}: {1}", "Symbol",settings.CurrencyDecimal.Symbol); } }
如上面的代码片段所示,我们创建一个ServiceCollection对象并调用扩展方法AddOptions注册于针对Option模型的服务。接下来我们调用Configure方法将FormatSettings这个Option类型与对应的Configuration对象进行映射。我们最后利用这个ServiceCollection对象生成一个ServiceProvider,并调用其GetService方法得到一个类型为IOptionsb7508df415eea39e792050f586bf7677的对象,后者的Value属性返回的就是绑定了相关配置的FormatSettings对象。
以上是解析ASP.NET Core配置教學之讀取設定資訊(建議)的詳細內容。更多資訊請關注PHP中文網其他相關文章!