我们创建了一个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对象来创建的。
CurrencyDecimalFormatOptionsDigits { get; set; }Symbol { get; set; }.Digits = int.Parse(config["Digits"]); 9: this.Symbol = config["Symbol"]; 10: } 11: }
我们定义了另一个名为FormatOptions的类型来表示针对不同数据类型的格式设置。如下面的代码片段所示,它的两个属性DateTime和CurrencyDecimal分别表示针对日期/时间和货币数字的格式设置。FormatOptions依然具有一个参数类型为IConfiguration接口的构造函数,它的两个属性均在此构造函数中被初始化。值得注意的是初始化这两个属性采用的是当前Configuration的“子配置节”,我们通过指定配置节名称调用GetSection方法获得这两个子配置节。
FormatOptionsCurrencyDecimalFormatOptions CurrencyDecimal { get; set; }.DateTime = new DateTimeFormatOptions (config.GetSection("DateTime")); 9: this.CurrencyDecimal = new CurrencyDecimalFormatOptions (config.GetSection("CurrencyDecimal")); 10: } 11: }
FormatOptions类型体现的配置具有如下图所示的树形层次化结构。在我们上面演示的实例中,我们通过以一个MemoryConfigurationSource对象来提供原始的配置信息。由于承载原始配置信息的是一个元素类型为KeyValuePair<string, string>的集合,它在物理存储上并不具有树形化的层次结构,那么它如何能够最终提供一个结构化的Configuration对象呢?
解决方案其实很简单,对于一棵完整的配置树,具体的配置信息最终是通过叶子节点来承载的,所以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)