1. 程式人生 > >.NET Core採用的全新配置系統[1]: 讀取配置資料

.NET Core採用的全新配置系統[1]: 讀取配置資料

提到“配置”二字,我想絕大部分.NET開發人員腦海中會立馬浮現出兩個特殊檔案的身影,那就是我們再熟悉不過的app.config和web.config,多年以來我們已經習慣了將結構化的配置定義在這兩個檔案之中。到了.NET Core的時代,很多我們習以為常的東西都發生了改變,其中也包括定義配置的方式。總的來說,新的配置系統顯得更加輕量級,並且具有更好的擴充套件性,其最大的特點就是支援多樣化的資料來源。我們可以採用記憶體的變數作為配置的資料來源,也可以直接配置定義在持久化的檔案甚至資料庫中。由於很多人都不曾接觸過這個採用全新設計的配置系統,為了讓大家對它有一個大體的認識,我們先從程式設計的角度來體驗一下全新的配置讀取方式。這個全新的配置系統為配置的讀取定義了非常簡單的API,這些API涉及到三個核心的物件,我們不妨稱之為“配置程式設計模型三要素

”。 [ 本文已經同步到《ASP.NET Core框架揭祕》之中]

目錄
一、配置程式設計模型三要素
二、以鍵-值對的形式讀取配置
三、讀取結構化的配置
四、將結構化配置直接繫結為物件

一、配置程式設計模型三要素

就程式設計層面來講,.NET Core的這個配置系統由如下圖所示的三個核心物件構成。讀取出來的配置資訊最終會轉換成一個Configuration物件供我們的程式使用。ConfigurationBuilder是Configuration物件的構建者,而ConfigurationSource則代表配置最原始的來源。

1

在讀取配置的時候,我們根據配置的定義方式建立相應的ConfigurationSource,並將其註冊到建立的ConfigurationBuilder物件上。由於提供配置的最初來源可能不止一個,所以我們可以註冊多個相同或者不同型別的ConfigurationSource物件到ConfigurationBuilder上。ConfigurationBuilder這是利用註冊的這些ConfigurationSource提供的原始資料最終構建出我們在程式中使用的Configuration物件。

根據本系列文章一貫採用的命名方式,我們應該知道上面介紹的Configuration、ConfigurationSource和ConfigurationBuilder均是對一類物件的統稱,它們在API層面都通過相應的介面(IConfiguration、IConfigurationSource和IConfigurationBuilder)來表示,這些介面均義在NuGet包“Microsoft.Extensions.Configuration.Abstractions”中。如果我們的程式中只需要使用到這些介面,我們只需要新增針對這個NuGet包的依賴。至於這些介面的預設實現型別,則大多定義在“Microsoft.Extensions.Configuration

”這個NuGet包中。

二、以鍵-值對的形式讀取配置

雖然在大部分情況下的配置從整體來說都具有結構化的次關係,但是“原子”配置項都以最簡單的“鍵-值對”的形式來體現,並且鍵和值通常都是字串,接下來我們會通過一個簡單的例項來演示如何以鍵值對的形式來讀取配置。我們建立一個針對ASP.NET Core的控制檯應用,並在project.json中按照如下的方式新增針對“Microsoft.Extensions.Configuration”這個NuGet包的依賴,配置模型就實現在這個包中。

   1: {
   2:   ...
   3:   "dependencies": {
   4:     "Microsoft.Extensions.Configuration": "1.0.0 "
   5:   },
   6: }

假設我們的應用程式需要通過配置來設定日期/時間的顯示格式,為此我們將相關的配置資訊定義在如下所示的這個DateTimeFormatOptions類,它的四個屬性體現針對DateTime物件的四種顯示格式(分別為長日期/時間和短日期/時間)。

   1: public class DateTimeFormatOptions
   2: {
   3:     public string LongDatePattern { get; set; }
   4:     public string LongTimePattern { get; set; }
   5:     public string ShortDatePattern { get; set; }
   6:     public string ShortTimePattern { get; set; }
   7:     //其他成員
   8: }

我們希望通過配置的形式來控制由DateTimeFormatOptions的四個屬性體現的日期/時間顯示格式,所以我們為它定義了一個建構函式。如下面的程式碼片段所示,該建構函式具有一個IConfiguration介面型別的引數,通過上面的介紹我們知道它是配置在應用程式中體現。鍵值對是配置的基本表現形式,所以Configuration物件提供了索引使我們可以根據配置項的Key得到配置項的值,下面的程式碼正式呼叫索引的方式得到對應配置資訊的。

   1: public class DateTimeFormatOptions
   2: {
   3:     //其他成員
   4:     public DateTimeFormatOptions (IConfiguration config)
   5:     {
   6:         this.LongDatePattern     = config ["LongDatePattern"];
   7:         this.LongTimePattern     = config ["LongTimePattern"];
   8:         this.ShortDatePattern    = config ["ShortDatePattern"];
   9:         this.ShortTimePattern    = config ["ShortTimePattern"];
  10:     }
  11: }

要建立一個體現當前配置的DateTimeFormatOptions物件,我們必須向得到這個承載相關配置資訊的Configuration物件。正如我們上面所說,Configuration物件是由ConfigurationBuilder建立的,而原始的配置資訊則是通過相應的ConfigurationSource來提取的,所以建立一個Configuration物件的正確程式設計方式是先建立一個ConfigurationBuilder物件,然後為之註冊一個或者多個ConfigurationSource物件,最後利用ConfigurationBuilder來建立我們需要的Configuration物件。

我們通過如下的程式來讀取配置並將其轉換成一個DateTimeFormatOptions物件。簡單起見,我們採用一中型別為MemoryConfigurationSource的ConfigurationSource,它直接利用一個儲存在記憶體中的字典物件作為最初的配置來源。如下面的程式碼片段所示,我們在為MemoryConfigurationSource提供的字典物件中設定了四種類型的日期/時間顯示格式。

   1: Dictionary<string, string> source = new Dictionary<string, string>
   2: {
   3:     ["longDatePattern"] = "dddd, MMMM d, yyyy",
   4:     ["longTimePattern"] = "h:mm:ss tt",
   5:     ["shortDatePattern"] = "M/d/yyyy",
   6:     ["shortTimePattern"] = "h:mm tt"
   7: };
   8:  
   9: IConfiguration config = new ConfigurationBuilder()
  10:     .Add(new MemoryConfigurationSource { InitialData = source })
  11:     .Build();
  12:  
  13: DateTimeFormatOptions options = new DateTimeFormatOptions(config);
  14: Console.WriteLine($"LongDatePattern: {options.LongDatePattern}");
  15: Console.WriteLine($"LongTimePattern: {options.LongTimePattern}");
  16: Console.WriteLine($"ShortDatePattern: {options.ShortDatePattern}");
  17: Console.WriteLine($"ShortTimePattern: {options.ShortTimePattern}");

我們建立了一個ConfigurationBuilder型別的物件,並將這個MemoryConfigurationSource註冊到它上面。接下來,我們直接呼叫ConfigurationBuilder的Build方法創建出Configuration物件,並利用後者建立了一個DateTimeFormatOptions物件。為了驗證DateTimeFormatOptions物件是否與原始的配置一致,我們將它的四個屬性列印在控制檯上。程式執行之後,控制檯上將會產生如下所示的輸出結果。

   1: LongDatePattern : dddd, MMMM d, yyyy
   2: LongTimePattern : h:mm:ss tt
   3: ShortDatePattern: M/d/yyyy
   4: ShortTimePattern: h:mm tt

三、讀取結構化的配置

真實專案中涉及的配置大都具有結構化的層次結構,所以Configuration物件同樣具有這樣的結構。結構化配置具有一個樹形層次結構,我們不妨將其稱之為“配置樹”,一個Configuration物件最終對應著這棵配置樹的某個節點,而整棵配置樹自然可以由根節點對應的Configuration物件來表示。以鍵值對體現的“原子配置項”一般對應於配置樹中不具有子節點的“葉子節點”。

接下來我們同樣以例項的方式來演示如何定義並讀取具有層次結構的配置。我們依然沿用上一節的應用場景,不過現在我們不僅僅需要設定日期/時間的格式,還需要設定其他資料型別的格式,比如表示貨幣的Decimal型別。為此我們定義瞭如下一個CurrencyDecimalFormatOptions類,它的屬性Digits和Symbol分別表示小數位數和貨幣符號,一個CurrencyDecimalFormatOptions物件依然是利用一個Configuration物件來建立的。

   1: public class CurrencyDecimalFormatOptions
   2: {
   3:     public int        Digits { get; set; }
   4:     public string     Symbol { get; set; }
   5:  
   6:     public CurrencyDecimalFormatOptions (IConfiguration config)
   7:     {
   8:         this.Digits = int.Parse(config["Digits"]);
   9:         this.Symbol = config["Symbol"];
  10:     }
  11: }

我們定義了另一個名為FormatOptions的型別來表示針對不同資料型別的格式設定。如下面的程式碼片段所示,它的兩個屬性DateTime和CurrencyDecimal分別表示針對日期/時間和貨幣數字的格式設定。FormatOptions依然具有一個引數型別為IConfiguration介面的建構函式,它的兩個屬性均在此建構函式中被初始化。值得注意的是初始化這兩個屬性採用的是當前Configuration的“子配置節”,我們通過指定配置節名稱呼叫GetSection方法獲得這兩個子配置節。

   1: public class FormatOptions
   2: {
   3:     public DateTimeFormatOptions            DateTime { get; set; }
   4:     public CurrencyDecimalFormatOptions     CurrencyDecimal { get; set; }
   5:  
   6:     public FormatOptions (IConfiguration config)
   7:     {
   8:         this.DateTime = new DateTimeFormatOptions (config.GetSection("DateTime"));
   9:         this.CurrencyDecimal = new CurrencyDecimalFormatOptions (config.GetSection("CurrencyDecimal"));
  10:     }
  11: }

FormatOptions型別體現的配置具有如下圖所示的樹形層次化結構。在我們上面演示的例項中,我們通過以一個MemoryConfigurationSource物件來提供原始的配置資訊。由於承載原始配置資訊的是一個元素型別為KeyValuePair<string, string>的集合,它在物理儲存上並不具有樹形化的層次結構,那麼它如何能夠最終提供一個結構化的Configuration物件呢?

2

解決方案其實很簡單,對於一棵完整的配置樹,具體的配置資訊最終是通過葉子節點來承載的,所以MemoryConfigurationSource只需要在配置字典中儲存葉子節點的資料即可。除此之外,為了描述配置樹的結構,配置字典需要將對應葉子節點在配置樹種的路徑作為Key。所以MemoryConfigurationSource可以採用下表所示的配置字典對配置數進行“扁平化”,路徑採用冒號(“:”)作為分隔符。

Key

Value

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

$

如下面的程式碼片段所示,我們按照表1所示的結構建立了一個Dictionary<string, string>物件,並利用它創建出MemoryConfigurationSource物件。在利用ConfigurationBuildr得到表示整個配置的Configuration物件之後,我們呼叫其GetSection方法得到名稱為“Format”的配置節,並利用後者建立一個FormatOptions。

   1: Dictionary<string, string> source = new Dictionary<string, string>
   2: {
   3:     ["format:dateTime:longDatePattern"] = "dddd, MMMM d, yyyy",
   4:     ["format:dateTime:longTimePattern"] = "h:mm:ss tt",
   5:     ["format:dateTime:shortDatePattern"] = "M/d/yyyy",
   6:     ["format:dateTime:shortTimePattern"] = "h:mm tt",
   7:  
   8:     ["format:currencyDecimal:digits"] = "2",
   9:     ["format:currencyDecimal:symbol"] = "$",
  10: };
  11: IConfiguration configuration = new ConfigurationBuilder()
  12:         .Add(new MemoryConfigurationSource { InitialData = source })
  13:         .Build();
  14:  
  15: FormatOptions options = new FormatOptions(configuration.GetSection("Format"));
  16: DateTimeFormatOptions dateTime = options.DateTime;
  17: CurrencyDecimalFormatOptions currencyDecimal = options.CurrencyDecimal;
  18:  
  19: Console.WriteLine("DateTime:");
  20: Console.WriteLine($"\tLongDatePattern: {dateTime.LongDatePattern}");
  21: Console.WriteLine($"\tLongTimePattern: {dateTime.LongTimePattern}");
  22: Console.WriteLine($"\tShortDatePattern: {dateTime.ShortDatePattern}");
  23: Console.WriteLine($"\tShortTimePattern: {dateTime.ShortTimePattern}");        
  24:  
  25: Console.WriteLine("CurrencyDecimal:");
  26: Console.WriteLine($"\tDigits:{currencyDecimal.Digits}");
  27: Console.WriteLine($"\tSymbol:{currencyDecimal.Symbol}");

在得到利用讀取的配置建立的 FormatOptions物件之後,為了驗證該物件與原始配置資料是否一致,我們依然將它的相關屬性列印在控制檯上。這個程式之後之後改程式會在控制檯上呈現如下所示的輸出結果。(S02)

相關推薦

.NET Core採用全新配置系統[1]: 讀取配置資料

提到“配置”二字,我想絕大部分.NET開發人員腦海中會立馬浮現出兩個特殊檔案的身影,那就是我們再熟悉不過的app.config和web.config,多年以來我們已經習慣了將結構化的配置定義在這兩個檔案之中。到了.NET Core的時代,很多我們習以為常的東西都發生了改變,其中也包括定義配置的方式。總的來說,

ASP.NET Core實現強類型Configuration讀取配置數據

控制器 項目 最好 前言實現讀取JSON文件幾種方式,在項目中采取老辦法簡單粗暴,結果老大過來一看,恩,這樣不太可取,行吧那我就用.NET Core中最新的方式諾,切記,適合的才是最好的,切勿懶。.NET Core讀取JSON文件通過讀取文件方式 當我將VS2015項目用VS2017打開後

ASP.NET Core實現類庫項目讀取配置文件

services 應用程序 配置文件 builder public .NET Core類庫項目讀取JSON配置文件在應用程序目錄下添加JSON文件是進行如下配置: var builder = new ConfigurationBuilder()

.NET Core採用全新配置系統[7]: 將配置儲存在資料庫中

我們在《聊聊預設支援的各種配置源》和《深入瞭解三種針對檔案(JSON、XML與INI)的配置源》對配置模型中預設提供的各種ConfigurationSource進行了深入詳盡的介紹,如果它們依然不能滿足專案中的配置需求,我們可以還可以通過自定義ConfigurationProvider來支援我們希望的配置來源

.NET Core採用全新配置系統[4]: “Options模式”下各種型別的Options物件是如何繫結的?

旨在生成Options物件的配置繫結實現在IConfiguration介面的擴充套件方法Bind上。配置繫結的目標型別可以是一個簡單的基元型別,也可以是一個自定義資料型別,還可以是一個陣列、集合或者字典型別。通過前面的介紹我們知道ConfigurationProvider將原始的配置資料讀取出來後會將其轉成K

.NET Core採用全新配置系統[2]: 配置模型設計詳解

在《.NET Core採用的全新配置系統[1]: 讀取配置資料》中,我們通過例項的方式演示了幾種典型的配置讀取方式,其主要目的在於使讀者朋友們從程式設計的角度對.NET Core的這個全新的配置系統具有一個大體上的認識,接下來我們從設計的維度來重寫認識它。通過上面演示的例項我們知道,配置的程式設計模型涉及到三

.NET Core採用全新配置系統[8]: 如何實現配置與原始檔的同步

配置的同步涉及到兩個方面:第一,對原始的配置檔案實施監控並在其發生變化之後從新載入配置;第二,配置重新載入之後及時通知應用程式進而使後者能夠使用最新的配置。接下來我們利用一個簡單的.NET Core控制檯應用來演示針對檔案的配置會涉及到資料同步的問題,我們希望應用能夠對原始配置檔案實施監控,並在檔案內容發生改

.NET Core採用全新配置系統[5]: 聊聊預設支援的各種配置源[記憶體變數,環境變數和命令列引數]

較之傳統通過App.config和Web.config這兩個XML檔案承載的配置系統,.NET Core採用的這個全新的配置模型的最大一個優勢就是針對多種不同配置源的支援。我們可以將記憶體變數、命令列引數、環境變數和物理檔案作為原始配置資料的來源,如果採用物理檔案作為配置源,我們可以選擇不同的格式(比如XML

.NET Core採用全新配置系統[6]: 深入瞭解三種針對檔案(JSON、XML與INI)的配置

物理檔案是我們最常用到的原始配置的載體,最佳的配置檔案格式主要由三種,它們分別是JSON、XML和INI,對應的配置源型別分別是JsonConfigurationSource、XmlConfigurationSource和IniConfigurationSource。 [ 本文已經同步到《ASP.NET Co

.NET Core採用全新配置系統[9]: 為什麼針對XML的支援不夠好?如何改進?

物理檔案是我們最常用到的原始配置的載體,最佳的配置檔案格式主要由三種,它們分別是JSON、XML和INI,對應的配置源型別分別是JsonConfigurationSource、XmlConfigurationSource和IniConfigurationSource。但是對於.NET Core的配置系統來說,

.NET Core採用全新配置系統[10]: 配置的同步機制是如何實現的?

配置的同步涉及到兩個方面:第一,對原始的配置檔案實施監控並在其發生變化之後從新載入配置;第二,配置重新載入之後及時通知應用程式進而使後者能夠使用最新的配置。要了解配置同步機制的實現原理,先得從認識一個名為ConfigurationReloadToken的型別開始。 [ 本文已經同步到《ASP.NET Core

.NET Core採用全新配置系統[3]: “Options模式”下的配置是如何繫結為Options物件

配置的原子結構就是單純的鍵值對,並且鍵和值都是字串,但是在真正的專案開發中我們一般不會單純地以鍵值對的形式來使用配置。值得推薦的做法就是採用《.NET Core採用的全新配置系統[1]: 讀取配置資料》最後演示的方式將相關的配置定義成一個Options型別,並採用與型別定義想匹配的結構來定義原始的配置,這樣就

菜鳥入門【ASP.NET Core】5:命令行配置、Json文件配置、Bind讀取配置到C#實例、在Core Mvc中使用Options

加載 中間 view tar public png 配置到 index 不同 命令行配置 我們通過vs2017創建一個控制臺項目CommandLineSample 可以看到現在項目以來的是dotnet core framework 我們需要吧a

.net core學習筆記《新一代的配置系統Configuration在支持多數據源,熱更新,層級化方面代碼快速實踐》

配置文件 stat variables ack lec 復制 image onf sof 在我們之前.Net Framework的項目中,配置文件是WebConfig或AppcConfig文件,而當我們想要添加我們自定義的節點時,還需要在這個文件中的section中定義我們

NET Core類庫專案中如何讀取appsettings json中的配置

                這是一位朋友問我的問題,寫篇隨筆回答一下。有2種方法,一種叫醜陋的方法 —— IConf

[ASP.NET Core 3框架揭祕] 配置[2]:讀取配置資料[下篇]

[接上篇]提到“配置”二字,我想絕大部分.NET開發人員腦海中會立即浮現出兩個特殊檔案的身影,那就是我們再熟悉不過的app.config和web.config,多年以來我們已經習慣了將結構化的配置定義在這兩個XML格式的檔案之中。到了.NET Core的時代,很多我們習以為常的東西都發

[ASP.NET Core 3框架揭祕] Options[1]: 配置選項的正確使用方式[上篇]

依賴注入不僅是支撐整個ASP.NET Core框架的基石,也是開發ASP.NET Core應用採用的基本程式設計模式,所以依賴注入十分重要。依賴注入使我們可以將依賴的功能定義成服務,最終以一種鬆耦合的形式注入消費該功能的元件或者服務中。除了採用依賴注入的形式消費承載某種功能的服務,還可以採用相同的方式消費承載

[ASP.NET Core 3框架揭祕] Options[7]: 與配置系統的整合

Options模型本身與配置系統完全沒有關係,但是配置在大部分情況下會作為繫結Options物件的資料來源,所以有必要將兩者結合在一起。與《擴充套件與定製》演示的兩個例子一樣,針對配置系統的整合同樣是通過定製Options模型相應的物件來實現的。具體來說,整合配置系統需要解決如下兩個問題:將承載配置資料的IC

在.NET Core中用最原生的方式讀取Nacos的配置

## 背景 之前老黃寫過一篇《ASP.NET Core結合Nacos來完成配置管理和服務發現》簡單介紹瞭如何讓.NET Core程式接入Nacos,之前的SDK裡面更多的是對Nacos的Open API進行了封裝以及對服務註冊和發現的封裝。 配置這一塊當時並沒有過多的處理,用起來有時感覺不會特別順手,所以

.net core 2.0 Code First Fluent API配置

asp 完成 eating cte word his text -1 src A.net core 2.0新特性支持通過IEntityTypeConfiguration<>添加Code First配置到一個封裝類。 新建目標框架為.NET Core類庫 新建完