Enterprise Library Step By Step系列(十五):配置應(yīng)用程序塊——設(shè)計(jì)篇
Enterprise Library Step By Step系列(十五):配置應(yīng)用程序塊——設(shè)計(jì)篇
Terrylee,
概述
配置應(yīng)用程序塊為應(yīng)用系統(tǒng)提供了一個(gè)通用的配置管理解決方案,可以方便的從各種存儲(chǔ)中讀取配置信息。在設(shè)計(jì)上旨在提供一個(gè)用于讀/寫(xiě)配置數(shù)據(jù)的簡(jiǎn)單接口,實(shí)現(xiàn)配置數(shù)據(jù)的讀寫(xiě)與數(shù)據(jù)的存儲(chǔ)相分離。使用Storage Provider 和 Transformers在應(yīng)用和物理存儲(chǔ)之間傳遞數(shù)據(jù),同時(shí)采用抽象AbstractFactory模式生成Provider數(shù)據(jù)。先解釋一下配置應(yīng)用程序塊中用到的兩個(gè)重要的概念:
Storage Provider是讀寫(xiě)某個(gè)物理存儲(chǔ)的對(duì)象,比如XML文件或SQL數(shù)據(jù)庫(kù)
Transformers是在存儲(chǔ)格式和應(yīng)用格式之間轉(zhuǎn)換配置數(shù)據(jù)的對(duì)象
結(jié)構(gòu)設(shè)計(jì)
下圖展示了組成配置應(yīng)用程序塊的類(lèi)和對(duì)象之間的關(guān)系。該圖假定您使用 XML 文件存儲(chǔ)提供程序和轉(zhuǎn)換器,它們包含在應(yīng)用程序塊中。XML 文件存儲(chǔ)提供程序以文件的形式存儲(chǔ)配置數(shù)據(jù)。(其他提供程序使用其他形式的存儲(chǔ),例如 Windows 注冊(cè)表。)XmlFileStorageProvider 對(duì)象指向一個(gè)包含特定配置節(jié)的配置設(shè)置的文件。ConfigurationBuilder 對(duì)象指向一個(gè)包含特定配置節(jié)的配置元數(shù)據(jù)的文件。通常,包含配置元數(shù)據(jù)的文件名為 App.config(對(duì)于基于 Windows 的應(yīng)用程序)或 Web.config(對(duì)于基于 Web 的應(yīng)用程序)。
配置應(yīng)用程序塊將配置元數(shù)據(jù)和實(shí)際的配置設(shè)置分隔開(kāi)來(lái)。應(yīng)用程序塊將元數(shù)據(jù)放在它自己的文件中,而該文件獨(dú)立于存儲(chǔ)配置設(shè)置的位置。配置設(shè)置經(jīng)過(guò)分組并稱(chēng)為配置節(jié)。應(yīng)用程序使用的每個(gè)企業(yè)程序庫(kù)應(yīng)用程序塊都有其自己的配置節(jié),該配置節(jié)存儲(chǔ)在其自己的文件中。配置應(yīng)用程序塊使用配置元數(shù)據(jù)來(lái)訪問(wèn)配置中的數(shù)據(jù)。
元數(shù)據(jù)指向配置存儲(chǔ)位置并包含一些信息,例如,配置應(yīng)用程序塊讀/寫(xiě)配置數(shù)據(jù)所需的轉(zhuǎn)換器和存儲(chǔ)提供程序的類(lèi)型。配置元數(shù)據(jù)文件被分成節(jié)。每一節(jié)都包含在配置存儲(chǔ)位置讀/寫(xiě)一組特定的配置設(shè)置所需的信息。下圖展示了元數(shù)據(jù)和配置區(qū)之間的關(guān)系:
ConfigurationManager 類(lèi)提供一個(gè)在所定義的存儲(chǔ)位置讀/寫(xiě)特定配置節(jié)的配置設(shè)置的靜態(tài)外觀(個(gè)人覺(jué)得是在這里運(yùn)用了門(mén)面模式,不知道對(duì)不對(duì)?)。ConfigurationManager 對(duì)象從應(yīng)用程序域配置文件讀取配置元數(shù)據(jù),然后使用這些信息來(lái)讀/寫(xiě)配置節(jié)信息。
ConfigurationManager 類(lèi)的靜態(tài)方法使用 ConfigurationBuilder 對(duì)象的實(shí)例。ConfigurationBuilder 可創(chuàng)建文件存儲(chǔ)提供程序和轉(zhuǎn)換器對(duì)象。這些對(duì)象可管理配置數(shù)據(jù)和元數(shù)據(jù)。
IStorageProviderReader 接口定義了用于從存儲(chǔ)位置讀取配置信息的接口。IStorageProviderWriter 接口實(shí)現(xiàn)了 IStorageProviderReader 接口,還定義了用于寫(xiě)入配置信息的接口。配置應(yīng)用程序塊包含一個(gè)支持該接口的提供程序 XmlFileStorageProvider,它在一個(gè) XML 文件中讀/寫(xiě)配置數(shù)據(jù)。
ITransformer 接口可轉(zhuǎn)換應(yīng)用程序和存儲(chǔ)提供程序之間的配置設(shè)置對(duì)象。配置應(yīng)用程序塊包含一個(gè)實(shí)現(xiàn)該接口的提供程序,即 XmlSerializerTransformer 類(lèi)。XmlSerializerTransformer 類(lèi)實(shí)現(xiàn)了應(yīng)用程序定義的運(yùn)行時(shí)對(duì)象和 XmlNode 對(duì)象之間的轉(zhuǎn)換,而無(wú)需應(yīng)用程序來(lái)配置轉(zhuǎn)換器。如果沒(méi)有轉(zhuǎn)換器,配置設(shè)置對(duì)象就會(huì)以存儲(chǔ)提供程序提供的相同格式返回到應(yīng)用程序。
每個(gè)配置節(jié)的設(shè)置都緩存在一個(gè)哈希表中。當(dāng)客戶端請(qǐng)求配置數(shù)據(jù)時(shí),ConfigurationBuilder 對(duì)象會(huì)在緩存中查找數(shù)據(jù)。如果在緩存中找到配置數(shù)據(jù),ConfigurationBuilder 對(duì)象就不必訪問(wèn)存儲(chǔ)中的配置數(shù)據(jù)。如果文件存儲(chǔ)提供程序檢測(cè)到存儲(chǔ)中的配置數(shù)據(jù)已經(jīng)更改,則 ConfigurationBuilder 對(duì)象就會(huì)清除緩存。ConfigurationManager 對(duì)象允許應(yīng)用程序清除全部緩存,或者只清除給定節(jié)名的緩存。如果清除了緩存,則下一個(gè)讀取操作就會(huì)訪問(wèn)存儲(chǔ)位置中的配置設(shè)置。
解耦
這個(gè)詞在配置應(yīng)用程序塊中得到了很好的體現(xiàn),將配置數(shù)據(jù)的讀寫(xiě)和配置數(shù)據(jù)的存儲(chǔ)分離。在配置應(yīng)用程序塊中已經(jīng)實(shí)現(xiàn)了讀寫(xiě)XML的Storage Provider,同時(shí)支持開(kāi)發(fā)者根據(jù)數(shù)據(jù)存儲(chǔ)的物理位置來(lái)編寫(xiě)相應(yīng)的Provider,見(jiàn)下圖:
如果我們編寫(xiě)了自己的Storage Provider和 Transformer,那么我們可以很簡(jiǎn)單的利用配置工具來(lái)修改數(shù)據(jù)的存儲(chǔ)而無(wú)須修改任何代碼(這也是整個(gè)企業(yè)庫(kù)的設(shè)計(jì)思想的體現(xiàn),配置驅(qū)動(dòng))。
簡(jiǎn)化配置
配置應(yīng)用程序塊做到讓開(kāi)發(fā)人員通過(guò)一行代碼來(lái)實(shí)現(xiàn)對(duì)配置數(shù)據(jù)的讀取和寫(xiě)入,下面的代碼展示了如何讀取和寫(xiě)入配置數(shù)據(jù):
/// 讀取配置數(shù)據(jù)2
MyConfigClass configData = ConfigurationManager.GetConfiguration("MySettings") as MyConfigClass;3

4
/// 寫(xiě)入配置數(shù)據(jù)5
ConfigurationManager.WriteConfiguration("MySettings", configData);而應(yīng)用程序塊在讀寫(xiě)配置數(shù)據(jù)時(shí),實(shí)際上是執(zhí)行了ConfigurationBuilder的ReadConfiguration()和WriteConfiguration()方法。ConfigurationManager類(lèi)通過(guò)外觀模式把這個(gè)兩個(gè)方法封裝成了上面所寫(xiě)的GetConfiguration()和WriteConfiguration()方法。
下面我們看一下具體的讀寫(xiě)代碼:
public object ReadConfiguration(string sectionName)2
{ 3
///驗(yàn)證有效性4
ValidateSection(sectionName);5
6
///變量configurationSection代表具體的配置數(shù)據(jù)類(lèi):MyConfigClass7
object configurationSection = sections.GetSection(sectionName);8
9
///緩存存在就直接返回結(jié)果10
if (IsConfigurationSectionCached(configurationSection))11
{12
return configurationSection;13
}14
15
IStorageProviderReader storageProviderReader = CreateStorageProvider(sectionName);16
17
///變量configurationSettings代表的是具體配置數(shù)據(jù)中的配置項(xiàng)物理格式的數(shù)據(jù)18
///核心功能,調(diào)用Read()方法,實(shí)際的讀取由Provider完成19
object configurationSettings = storageProviderReader.Read();20
if (configurationSettings == null)21
{22
return null;23
}24

25
ITransformer transformer = CreateTransformer(sectionName);26
if (transformer != null)27
{28
///將配置數(shù)據(jù)由代表物理格式配置數(shù)據(jù)的類(lèi)轉(zhuǎn)變?yōu)榇響?yīng)用程序直接訪問(wèn)的配置類(lèi)29
configurationSection = transformer.Deserialize(configurationSettings);30
}31
else32
{33
configurationSection = configurationSettings;34
}35

36
ConfigurationChangedEventHandler changed = new ConfigurationChangedEventHandler(OnExternalConfigurationChanged);37
38
///增加到緩存中39
sections.AddSection(sectionName, configurationSection, changed, storageProviderReader);40

41
return configurationSection;42
}
public void WriteConfiguration(string sectionName, object configValue)2
{ 3
///驗(yàn)證有效性4
ValidateSection(sectionName);5
6
///注冊(cè)寫(xiě)前事件7
ConfigurationChangingEventArgs args = CreateConfigurationChangingEventArgs(sectionName, configValue);8
OnConfigurationChanging(args);9
if (!args.Cancel)10
{11
///創(chuàng)建編寫(xiě)器12
IStorageProviderWriter configStorageWriter = GetConfigurationStorageWriter(sectionName);13
14
///將要保存的值轉(zhuǎn)換成Provider可識(shí)別的格式,具體何種格式是由配置元數(shù)據(jù)決定的15
object writeData = GetSerializedDataToWrite(sectionName, configValue);16
ConfigurationWriterActionCommand writerActionCommand = new ConfigurationWriterActionCommand(configStorageWriter, writeData);17
18
///如果配置節(jié)尚不存在就添加此配置數(shù)據(jù)19
if (!sections.ContainsSection(sectionName))20
{21
AddSection(sectionName, configValue, configStorageWriter);22
}23
24
///如果配置節(jié)已存在就更新此配置數(shù)據(jù)25
sections.UpdateSection(sectionName, writerActionCommand, configValue);26
27
///注冊(cè)寫(xiě)完成事件28
ConfigurationChangedEventArgs changedArgs = new ConfigurationChangedEventArgs(configFile.FileName, sectionName);29
OnConfigurationChanged(changedArgs);30
}31
}擴(kuò)展器和工廠
由于找不到更好的中文字來(lái)說(shuō)明Provider,所以只好用了擴(kuò)展器這個(gè)名字,大家見(jiàn)諒。來(lái)看一下配置應(yīng)用程序塊中的Providers結(jié)構(gòu)圖:
IConfigurationProvider 接口是所有的Providers必須實(shí)現(xiàn)的,以便配置應(yīng)用程序塊能夠創(chuàng)建和初始化它們。該接口中有一個(gè)方法Initialize()和一個(gè)屬性ConfigurationName,配置應(yīng)用程序塊調(diào)用Initialize()方法來(lái)創(chuàng)建每一個(gè)Providers。
配置應(yīng)用程序塊中包含了一個(gè)抽象的基類(lèi)ConfigurationProvider。它實(shí)現(xiàn)了IConfigurationProvider 接口中的ConfigurationName屬性。
配置應(yīng)用程序塊中的Factories結(jié)構(gòu)圖:
ConfigurationFactory是一個(gè)抽象的基類(lèi),它定義了應(yīng)用程序塊中所有的工廠類(lèi)的接口,所有的Factory類(lèi)必須從它繼承。ProviderFactory類(lèi)實(shí)現(xiàn)了IConfigurationProvider并從ConfigurationFactory類(lèi)繼承,也是一個(gè)抽象類(lèi)。
總結(jié)
好了,這里引用M
Worktile,新一代簡(jiǎn)單好用、體驗(yàn)極致的團(tuán)隊(duì)協(xié)同、項(xiàng)目管理工具,讓你和你的團(tuán)隊(duì)隨時(shí)隨地一起工作。完全免費(fèi),現(xiàn)在就去了解一下吧。
https://worktile.com



浙公網(wǎng)安備 33010602011771號(hào)