原文引自:
http://www.microsoft.com/china/msdn/library/architecture/architecture/architecturetopic/SCArchDeGuide/Chapter1Introduction.mspx
Offline Application Block 的設(shè)計(jì)
發(fā)布日期: 8/6/2004 | 更新日期: 8/6/2004
Microsoft Corporation
摘要:第 2 章討論 Offline Application Block 的設(shè)計(jì)。
本頁(yè)內(nèi)容
Offline Application Block 是根據(jù) .NET 框架的功能并封裝智能客戶端應(yīng)用程序來(lái)構(gòu)建的,以幫助用戶在脫機(jī)時(shí)執(zhí)行任務(wù),就像用戶在聯(lián)機(jī)時(shí)執(zhí)行任務(wù)一樣簡(jiǎn)單而有效。本章說(shuō)明 Offline Application Block 的設(shè)計(jì)、功能以及融入其設(shè)計(jì)的決策。
脫機(jī)挑戰(zhàn)
智能客戶端應(yīng)用程序的開(kāi)發(fā)人員在設(shè)計(jì)可以聯(lián)機(jī)和脫機(jī)運(yùn)行的程序時(shí),必須解決許多問(wèn)題。通常發(fā)生的問(wèn)題包括:
? |
應(yīng)用程序如何確定它處于聯(lián)機(jī)狀態(tài)還是脫機(jī)狀態(tài)? |
? |
如果連接能夠以不可預(yù)計(jì)的次數(shù)進(jìn)行更改,那么應(yīng)該如何通知依賴于連接狀態(tài)的應(yīng)用程序組件呢? |
? |
應(yīng)用程序應(yīng)該如何存儲(chǔ)數(shù)據(jù)以及將數(shù)據(jù)存儲(chǔ)在本地的什么地方,才能在脫機(jī)狀態(tài)下對(duì)其進(jìn)行訪問(wèn)?數(shù)據(jù)會(huì)變陳舊嗎?應(yīng)該在何時(shí)刷新數(shù)據(jù)? |
? |
當(dāng)應(yīng)用程序無(wú)法訪問(wèn)所有必需的數(shù)據(jù)或服務(wù)時(shí),是否應(yīng)采用不同的運(yùn)作方式? |
? |
當(dāng)應(yīng)用程序處于脫機(jī)狀態(tài)時(shí),應(yīng)如何存儲(chǔ)事務(wù)性數(shù)據(jù)(消息數(shù)據(jù)),以及在何處存儲(chǔ)這些數(shù)據(jù)? |
? |
當(dāng)應(yīng)用程序從脫機(jī)變?yōu)槁?lián)機(jī)時(shí),應(yīng)如何將事務(wù)性數(shù)據(jù)與服務(wù)器同步? |
解決方案說(shuō)明
Offline Application Block 可以提供具有脫機(jī)功能的智能客戶端應(yīng)用程序所需的基本功能。其基本功能包括:
? |
檢測(cè)網(wǎng)絡(luò)連接是否存在。 |
? |
當(dāng)連接狀態(tài)變更時(shí)通知所有已注冊(cè)的組件。 |
? |
下載并緩存參考數(shù)據(jù),以便在網(wǎng)絡(luò)連接不可用時(shí)允許應(yīng)用程序正常工作。 |
? |
當(dāng)應(yīng)用程序脫機(jī)時(shí),在本地存儲(chǔ)消息數(shù)據(jù)。 |
? |
當(dāng)網(wǎng)絡(luò)連接變?yōu)榭捎脮r(shí),將消息數(shù)據(jù)與服務(wù)器進(jìn)行同步。 |
設(shè)計(jì)目標(biāo)
Offline Application Block 旨在用作要將脫機(jī)功能包括在其應(yīng)用程序中的開(kāi)發(fā)人員的體系結(jié)構(gòu)指南。該應(yīng)用程序塊的設(shè)計(jì)目標(biāo)為:
? |
在組件之間提供松耦合。 |
? |
抽象化應(yīng)用程序的連接狀態(tài)管理。 |
? |
為聯(lián)機(jī)和脫機(jī)模式下的應(yīng)用程序提供相同的編程模型,這樣應(yīng)用程序在這兩種模式之間的轉(zhuǎn)換不會(huì)影響用戶體驗(yàn)。 |
? |
為諸如連接檢測(cè)和排隊(duì)這樣的功能提供可擴(kuò)展的接口。 |
? |
合并設(shè)計(jì)模式。 |
設(shè)計(jì)注意事項(xiàng)
應(yīng)用程序塊體系結(jié)構(gòu)提倡使用可重復(fù)使用的封裝代碼組件。理想情況下,這些組件可設(shè)計(jì)為既可以互操作,又是模塊化的,以便代碼可以直接重復(fù)使用。在應(yīng)用程序中引用某個(gè)塊可以為應(yīng)用程序提供該塊的功能。
Offline Application Block 設(shè)計(jì)可提供邏輯和物理構(gòu)建塊,開(kāi)發(fā)人員需要使用這些構(gòu)建塊將脫機(jī)功能合并到他們的應(yīng)用程序中。成功支持脫機(jī)操作的能力并不是通過(guò)簡(jiǎn)單地添加構(gòu)建塊并調(diào)整現(xiàn)有的應(yīng)用程序就可以獲得。該構(gòu)建塊設(shè)計(jì)為推薦做法的一個(gè)示例 — 所提供的代碼僅闡述了可能的解決方案。在設(shè)計(jì)階段仔細(xì)計(jì)劃可以確保您的 Offline Application Block 應(yīng)用程序既可以重復(fù)使用又可以擴(kuò)展。
模式
模式是可重復(fù)使用的解決方案,用于解決程序員可能在類似環(huán)境中遇到的重復(fù)出現(xiàn)的設(shè)計(jì)問(wèn)題。在 Offline Application Block 的設(shè)計(jì)中使用了幾種模式,如表 2.1 中所述。
Builder |
從已創(chuàng)建組件的應(yīng)用程序邏輯中分離復(fù)雜的創(chuàng)建邏輯。允許應(yīng)用程序類的客戶端在創(chuàng)建塊組件的過(guò)程中保持獨(dú)立。 |
Factory |
構(gòu)建一個(gè)用于創(chuàng)建對(duì)象的接口,該接口應(yīng)在創(chuàng)建對(duì)象時(shí)允許子類選擇要實(shí)例化的類。 |
Observer |
在對(duì)象之間使用一對(duì)多的關(guān)系以獲得及時(shí)有效的通知。當(dāng)?shù)谝粋€(gè)對(duì)象更改時(shí),所有相關(guān)的對(duì)象會(huì)立即獲得通知并自動(dòng)進(jìn)行更新。 |
Singleton |
提供對(duì)某個(gè)服務(wù)的單一、全局訪問(wèn)點(diǎn)。Singleton 可用于只允許創(chuàng)建特定類的一個(gè)實(shí)例,并在需要該實(shí)例時(shí)提供對(duì)該單一實(shí)例的訪問(wèn)。 |
Strategy |
提供定義一系列類似算法和接口(通過(guò)其訪問(wèn)這些算法)的能力。所使用的特定算法的實(shí)現(xiàn)可以在不同時(shí)更改客戶端類的情況下進(jìn)行更改。 |
Offline Application Block 設(shè)計(jì)
本部分說(shuō)明了組成 Offline Application Block 的主要子系統(tǒng)的過(guò)程和體系結(jié)構(gòu)。有關(guān)主要子系統(tǒng)如何協(xié)同工作的詳細(xì)說(shuō)明,請(qǐng)參閱本章的“請(qǐng)求和響應(yīng)往返”部分。
注 本部分只提供每個(gè)子系統(tǒng)類中最重要的方法和屬性的介紹。有關(guān)這些類及其成員的詳細(xì)信息,請(qǐng)參閱該應(yīng)用程序塊隨附的幫助文件。它位于 <安裝目錄>\Offline\Docs\ 文件夾中。
圖 2.1 展示了構(gòu)成脫機(jī)應(yīng)用程序的物理元素。
圖 2.1.Offline Application Block 的物理視圖
表 2.1 描述了圖 2.1 中的每個(gè)組件。這些組件將在本章中詳細(xì)討論。
連接檢測(cè)策略 |
連接狀態(tài)管理 |
檢測(cè)物理連接的當(dāng)前狀態(tài) |
ConnectionManager |
連接狀態(tài)管理 |
管理與物理網(wǎng)絡(luò)訪問(wèn)相關(guān)的連接狀態(tài)服務(wù)。使用可插入的連接檢測(cè)組件(通過(guò)實(shí)現(xiàn) IConnectionDetectionStrategy 接口)來(lái)確定連接狀態(tài)。當(dāng)“連接檢測(cè)策略”通知 ConnectionManager 連接狀態(tài)發(fā)生了變化,它就會(huì)觸發(fā)一個(gè)事件。ConnectionManager 還具有一些公共方法,應(yīng)用程序可以調(diào)用這些方法來(lái)手動(dòng)更改應(yīng)用程序的聯(lián)機(jī)/脫機(jī)狀態(tài)。 |
Executor |
消息數(shù)據(jù)管理 |
在聯(lián)機(jī)時(shí),從隊(duì)列中提取消息,并調(diào)用負(fù)責(zé)將消息發(fā)送到遠(yuǎn)程服務(wù)的“聯(lián)機(jī)代理”。此外,它還負(fù)責(zé)將來(lái)自遠(yuǎn)程服務(wù)的響應(yīng)發(fā)送回應(yīng)用程序。 |
隊(duì)列存儲(chǔ) |
消息數(shù)據(jù)管理 |
提供用于保存消息數(shù)據(jù)的數(shù)據(jù)存儲(chǔ)區(qū),以及將在應(yīng)用程序再次聯(lián)機(jī)時(shí)發(fā)送給服務(wù)器的操作。 |
QueueManager |
消息數(shù)據(jù)管理 |
用作“隊(duì)列存儲(chǔ)提供程序”的一個(gè)接口。它提供消息入列和消息出列的方法。 |
DataLoaderManager |
參考數(shù)據(jù)管理 |
提供一種工具,以允許應(yīng)用程序在適當(dāng)?shù)臅r(shí)間請(qǐng)求要下載的參考數(shù)據(jù),以便在操作過(guò)程中使用。 |
ReferenceDataCache |
參考數(shù)據(jù)管理 |
用作“參考數(shù)據(jù)管理”子系統(tǒng)的一個(gè)接口。它負(fù)責(zé)確保應(yīng)用程序所需的數(shù)據(jù)已存儲(chǔ),并可以在應(yīng)用程序處于脫機(jī)狀態(tài)時(shí)進(jìn)行本地訪問(wèn)(緩存)。 |
緩存塊 |
參考數(shù)據(jù)管理 |
提供一個(gè)物理緩存操作的實(shí)現(xiàn)。 |
應(yīng)用程序服務(wù)代理 |
服務(wù)代理管理 |
提供隊(duì)列消息的能力。它還提供了一個(gè)將結(jié)果返回應(yīng)用程序的通道。 |
Online Proxy |
服務(wù)代理管理 |
由應(yīng)用程序開(kāi)發(fā)人員創(chuàng)建的類,它負(fù)責(zé)與提供業(yè)務(wù)功能的遠(yuǎn)程服務(wù)進(jìn)行通信。如果需要,“聯(lián)機(jī)代理”還可以負(fù)責(zé)在緩存中存儲(chǔ)參考數(shù)據(jù)。 |
ServiceAgent |
服務(wù)代理管理 |
提供由應(yīng)用程序提供的所有服務(wù)代理所實(shí)現(xiàn)的基類。“服務(wù)代理”基類負(fù)責(zé)在服務(wù)代理注冊(cè)表中注冊(cè)服務(wù)代理。 |
ServiceAgentManager |
服務(wù)代理管理 |
處理后,“服務(wù)代理管理器”會(huì)將結(jié)果返回到相應(yīng)的“服務(wù)代理”。 |
說(shuō)明性方案
以下方案顯示了用戶所采取的操作如何轉(zhuǎn)換為在智能客戶端應(yīng)用程序內(nèi)部發(fā)生的操作。有關(guān)構(gòu)成 Offline Application Block 的元素是如何協(xié)同工作的整體概述,請(qǐng)參閱前面的圖 2.1。
準(zhǔn)備脫機(jī)工作
David 已連接到網(wǎng)絡(luò),并且正在運(yùn)行用于填寫其責(zé)任區(qū)域的保險(xiǎn)理賠的應(yīng)用程序。他按計(jì)劃到現(xiàn)場(chǎng)處理這個(gè)理賠。David 單擊“Download Work Items”按鈕以下載他需要完成的所有理賠。
應(yīng)用程序操作
在運(yùn)行時(shí),應(yīng)用程序?qū)m當(dāng)?shù)摹皯?yīng)用程序服務(wù)代理”進(jìn)行方法調(diào)用以下載數(shù)據(jù)。然后,“應(yīng)用程序服務(wù)代理”再調(diào)用 DataLoaderManager 以初始化下載。DataLoaderManager 調(diào)用 QueueManager,并將數(shù)據(jù)下載請(qǐng)求置于隊(duì)列中。如果系統(tǒng)處于聯(lián)機(jī)狀態(tài),則 Executor 將提取該請(qǐng)求,然后通過(guò)反射創(chuàng)建 OnlineProxy 的實(shí)例并調(diào)用指定的方法來(lái)處理該請(qǐng)求。然后,“聯(lián)機(jī)代理”與遠(yuǎn)程服務(wù)器進(jìn)行通信并獲得所需的數(shù)據(jù)。它通過(guò)使用 ReferenceDataCache 將數(shù)據(jù)存儲(chǔ)在本地計(jì)算機(jī)的緩存中。然后,Executor 調(diào)用“服務(wù)代理管理器”以返回結(jié)果。接下來(lái),“服務(wù)代理管理器”對(duì)特定“應(yīng)用程序服務(wù)代理”進(jìn)行回調(diào)。最后,“應(yīng)用程序服務(wù)代理”引發(fā)一個(gè)事件來(lái)通知應(yīng)用程序有關(guān)已下載數(shù)據(jù)的信息。
圖 2.2 闡釋了應(yīng)用程序用于下載參考數(shù)據(jù)的過(guò)程。
注 Offline Application Block 會(huì)保留部分緩存,并將其命名為“參考數(shù)據(jù)緩存”。該緩存只管理參考數(shù)據(jù)。您可以使用為您的組織而設(shè)計(jì)的數(shù)據(jù)存儲(chǔ)區(qū)來(lái)創(chuàng)建新緩存。
圖 2.2.下載參考數(shù)據(jù)時(shí)涉及的塊的各個(gè)部分
脫機(jī)工作
David 隨身攜帶了計(jì)算機(jī)。當(dāng)他再次訪問(wèn)該應(yīng)用程序時(shí),計(jì)算機(jī)沒(méi)有連接到網(wǎng)絡(luò),應(yīng)用程序是在脫機(jī)模式下啟動(dòng)的。David 在與他的客戶協(xié)商后完成了理賠。
應(yīng)用程序操作
應(yīng)用程序向 ConnectionManager 注冊(cè)以接收連接狀態(tài)更改事件。ConnectionManager 將使用 ConnectionDetectionStrategy 來(lái)確定計(jì)算機(jī)處于脫機(jī)狀態(tài),并觸發(fā)一個(gè)事件以通知所有注冊(cè)的組件。
注 組件必須向“連接管理器”注冊(cè),才能收到狀態(tài)更改事件的通知。
圖 2.3 闡釋了應(yīng)用程序用于檢測(cè)與網(wǎng)絡(luò)的連接性的過(guò)程。
圖 2.3.脫機(jī)過(guò)程中涉及的塊的各個(gè)組件
完成理賠
David 在應(yīng)用程序中打開(kāi)一個(gè)理賠,完成該理賠,然后單擊“Submit”按鈕。
應(yīng)用程序操作
應(yīng)用程序會(huì)在內(nèi)部調(diào)用“應(yīng)用程序服務(wù)代理”來(lái)處理工作項(xiàng)目。“服務(wù)代理”將創(chuàng)建一個(gè)包含該工作項(xiàng)目的 Payload。在創(chuàng)建 Payload 之后,“服務(wù)代理”會(huì)調(diào)用“隊(duì)列管理器”將消息數(shù)據(jù)存儲(chǔ)在隊(duì)列中。QueueManager 將 Payload 封裝在一個(gè) QueueMessage 中,并將其保留在隊(duì)列中。
圖 2.4 闡釋了應(yīng)用程序用于在脫機(jī)狀態(tài)下完成理賠的過(guò)程。
圖 2.4.在脫機(jī)狀態(tài)下完成理賠所涉及的塊的各個(gè)部分
同步脫機(jī)數(shù)據(jù)
David 返回辦公室,將計(jì)算機(jī)連接到網(wǎng)絡(luò),然后啟動(dòng)應(yīng)用程序。
應(yīng)用程序操作
一旦連接狀態(tài)變?yōu)槁?lián)機(jī),就會(huì)在單獨(dú)的線程上激活 Executor。然后,Executor 開(kāi)始檢索隊(duì)列中的隊(duì)列消息。對(duì)于每個(gè) QueueMessage,Executor 會(huì)調(diào)用 OnlineProxy(這是一個(gè)使用反射創(chuàng)建的對(duì)象,它使用 Payload 中包含的 onlineProxyContext 信息)的指定方法,將工作項(xiàng)目信息提交到遠(yuǎn)程服務(wù)以便進(jìn)行處理。處理工作項(xiàng)目后,遠(yuǎn)程服務(wù)會(huì)將結(jié)果返回到 Executor。
然后,Executor 將包含結(jié)果的 Payload 返回到“服務(wù)代理管理器”,隨后該管理器會(huì)在 ServiceAgentRegistry 中查找“應(yīng)用程序服務(wù)代理”。它將響應(yīng)發(fā)送到該“應(yīng)用程序服務(wù)代理”。“應(yīng)用程序服務(wù)代理”會(huì)在更新數(shù)據(jù)時(shí)通知用戶界面。所有理賠都以透明的方式進(jìn)行同步。
如果消息執(zhí)行失敗,并且原來(lái)的“應(yīng)用程序服務(wù)代理”不再可用,則“服務(wù)代理管理器”會(huì)將響應(yīng)發(fā)送到 FailsafeServiceAgent。
圖 2.5 闡釋了“服務(wù)代理管理”子系統(tǒng)執(zhí)行的步驟。
圖 2.5.添加脫機(jī)數(shù)據(jù)時(shí)所涉及的塊的各個(gè)部分
Offline Application Block 子系統(tǒng)
子系統(tǒng)的標(biāo)準(zhǔn)定義是:一起工作以完成指定目標(biāo)的一組獨(dú)立的類。通過(guò)將 Offline Application Block 劃分為下列邏輯子系統(tǒng),可以充分地理解它:
? |
連接狀態(tài)管理 |
? |
服務(wù)代理管理 |
? |
消息數(shù)據(jù)管理 |
? |
參考數(shù)據(jù)管理 |
? |
實(shí)用工具服務(wù) |
“連接狀態(tài)管理”子系統(tǒng)監(jiān)視應(yīng)用程序的聯(lián)機(jī)/脫機(jī)狀態(tài),并通知已注冊(cè)的偵聽(tīng)器。“連接狀態(tài)管理”可處理所有連接狀態(tài)任務(wù)(那些與檢測(cè)物理連接相關(guān)的任務(wù)),并且可以進(jìn)行擴(kuò)展,以檢測(cè)并連接到某個(gè)服務(wù),并可以檢測(cè)服務(wù)在何時(shí)不可用。
“服務(wù)代理管理”子系統(tǒng)控制“應(yīng)用程序服務(wù)代理”以及與 Executor 類的接口。
“消息數(shù)據(jù)管理”和“參考數(shù)據(jù)管理”子系統(tǒng)協(xié)同工作,以確保首次嘗試訪問(wèn)數(shù)據(jù)項(xiàng)目時(shí)數(shù)據(jù)的可用性。
“實(shí)用工具服務(wù)”管理連接性和非池線程 — 這意味著,線程管理對(duì)開(kāi)發(fā)人員是透明的。
下列各部分給出了有關(guān)每個(gè)子系統(tǒng)的詳細(xì)信息。
連接狀態(tài)管理
“連接狀態(tài)管理”子系統(tǒng)的主要角色是:檢測(cè)連接狀態(tài)并通知偵聽(tīng)器任何狀態(tài)變化。要擴(kuò)展其智能客戶端應(yīng)用程序以包含脫機(jī)功能的開(kāi)發(fā)人員,可能希望將應(yīng)用程序設(shè)計(jì)為在聯(lián)機(jī)工作和脫機(jī)工作時(shí)具有不同的行為。應(yīng)用程序是處于聯(lián)機(jī)狀態(tài)還是脫機(jī)狀態(tài),由下列兩個(gè)因素的其中一個(gè)決定:
? |
常規(guī)網(wǎng)絡(luò)連接是否存在 — 應(yīng)用程序是否能夠訪問(wèn)遠(yuǎn)程資源和服務(wù)? |
? |
來(lái)自應(yīng)用程序用戶的明確指令。應(yīng)用程序可能允許用戶將連接狀態(tài)設(shè)置為脫機(jī),即使第一個(gè)因素指示應(yīng)用程序處于聯(lián)機(jī)狀態(tài)。 |
類設(shè)計(jì)
“連接狀態(tài)管理”子系統(tǒng)包含的類可管理連接檢測(cè)和通知服務(wù)以及線程管理組件。這些類包括 ConnectionManager 類和 ConnectionDetector 類。
ConnectionManager 類
ConnectionManager 類是“連接狀態(tài)管理”子系統(tǒng)的一個(gè)接口,并且是 Observer 模式的一個(gè)示例。它負(fù)責(zé)管理連接狀態(tài)變化的檢測(cè),以及在發(fā)生變化時(shí)通知相應(yīng)的對(duì)象。它還提供了用于強(qiáng)制應(yīng)用程序脫機(jī)或聯(lián)機(jī)的方法。
類成員
以下部分(“方法”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請(qǐng)參閱該應(yīng)用程序塊中隨附的幫助文件。
方法
? |
GoOffline – 強(qiáng)制系統(tǒng)脫機(jī)。 |
? |
GoOnline – 強(qiáng)制系統(tǒng)聯(lián)機(jī)。 |
ConnectionDetector 類
ConnectionDetector 類管理發(fā)生的狀態(tài)轉(zhuǎn)換,這些轉(zhuǎn)換是由派生的 IConnectionDetectionStrategy 接口實(shí)現(xiàn)檢測(cè)到的。IConnectionDetectionStrategy 接口提供了檢測(cè)物理連接當(dāng)前狀態(tài)的功能,而 ConnectionDetector 類提供了檢測(cè)狀態(tài)變化的功能。
IConnectionDetectionStrategy 接口
“連接狀態(tài)管理”子系統(tǒng)支持不同的連接檢測(cè)實(shí)現(xiàn)(也稱為提供程序),以檢測(cè)連接是否存在。該子系統(tǒng)使用 Strategy 模式,可允許在不更改應(yīng)用程序代碼的情況下更改連接檢測(cè)算法。每個(gè)連接檢測(cè)提供程序都必須實(shí)現(xiàn) IConnectionDetectionStrategy 接口,以便該提供程序可以與應(yīng)用程序塊一起使用。
通過(guò)實(shí)現(xiàn)該接口并在應(yīng)用程序的配置文件中指定必要的配置信息,應(yīng)用程序開(kāi)發(fā)人員可以創(chuàng)建他們自己的連接檢測(cè)策略。
盡管可以在配置文件中定義多個(gè)策略,但只應(yīng)該在配置文件中啟用其中一個(gè)策略。
該應(yīng)用程序塊附帶一個(gè)名為 WinInetDetectionStrategy 的連接檢測(cè)提供程序,它使用 Windows 網(wǎng)絡(luò) API (WinInet) 來(lái)檢測(cè)網(wǎng)絡(luò)連接是否存在。有關(guān)詳細(xì)信息,請(qǐng)參閱本指南隨附的幫助文件。
服務(wù)代理管理
“服務(wù)代理管理”子系統(tǒng)執(zhí)行下列操作:
? |
維護(hù)“應(yīng)用程序服務(wù)代理”的注冊(cè)表 |
? |
包含負(fù)責(zé)在處理請(qǐng)求后將結(jié)果返回給“應(yīng)用程序服務(wù)代理”的組件 |
? |
提供應(yīng)用程序開(kāi)發(fā)人員用于實(shí)現(xiàn)應(yīng)用程序服務(wù)代理所必需的“服務(wù)代理”基類 |
設(shè)計(jì)用于 Offline Application Block 的“服務(wù)代理”
正如第 1 章中討論的那樣,Offline Application Block 使用面向服務(wù)的方法為智能客戶端應(yīng)用程序提供脫機(jī)功能。使用該方法,“服務(wù)代理”可以與提供各種業(yè)務(wù)功能的不同類型的遠(yuǎn)程服務(wù)一起工作。這些業(yè)務(wù)功能可作為 Web 服務(wù)在服務(wù)器端公開(kāi)。“服務(wù)代理”也需要與“緩存管理”、“隊(duì)列管理”和“消息數(shù)據(jù)管理”子系統(tǒng)進(jìn)行交互。
由于這些交互,“服務(wù)代理”可能要在這些子系統(tǒng)之間進(jìn)行多次往返。您可以設(shè)計(jì)一個(gè)具有不同任務(wù)粒度級(jí)別的“服務(wù)代理”。您還可以在“服務(wù)代理”與遠(yuǎn)程服務(wù)進(jìn)行通信時(shí)添加粒度。這些方法可以包含:
? |
與單個(gè)任務(wù)進(jìn)行交互的“服務(wù)代理”。例如,它可以創(chuàng)建一個(gè)客戶。 |
? |
與和某個(gè)實(shí)體相關(guān)的所有任務(wù)進(jìn)行交互的“服務(wù)代理”。例如,它可以在客戶實(shí)體上執(zhí)行創(chuàng)建、讀取、更新和刪除操作。 |
? |
只處理一個(gè)特定服務(wù)的“服務(wù)代理” |
? |
處理多個(gè)服務(wù)的“服務(wù)代理” |
在 Offline Application Block 的設(shè)計(jì)中,“服務(wù)代理”的責(zé)任劃分為兩個(gè)類:它們是:
? |
ServiceAgent – 該類在塊中本地執(zhí)行所有任務(wù)。這些任務(wù)可以包括創(chuàng)建和排列 Payload、更新本地緩存或從本地緩存中檢索滿足該請(qǐng)求所需的所有數(shù)據(jù)。在設(shè)計(jì)新的脫機(jī)塊時(shí),開(kāi)發(fā)人員應(yīng)該從 Offline Application Block 提供的 ServiceAgent 類中派生一個(gè)新的“應(yīng)用程序服務(wù)代理”類。 |
? |
OnlineProxy – 該類抽象了與提供業(yè)務(wù)功能的服務(wù)進(jìn)行交互的功能。應(yīng)用程序開(kāi)發(fā)人員必須創(chuàng)建他們自己的“聯(lián)機(jī)代理”。 |
使用兩個(gè)類(而不是單個(gè)類)的原因是:當(dāng) Offline Application Block 需要與 Web 服務(wù)進(jìn)行通信時(shí),需要?jiǎng)?chuàng)建并使用多個(gè)代理。為此,這些代理應(yīng)是無(wú)狀態(tài)的。
類設(shè)計(jì)
“服務(wù)代理管理”子系統(tǒng)包括要從 Executor 中獲取響應(yīng)、然后將結(jié)果傳回“應(yīng)用程序服務(wù)代理”的類。如果出現(xiàn)錯(cuò)誤并且原來(lái)的“應(yīng)用程序服務(wù)代理”不可用,則錯(cuò)誤被傳遞到“Failsafe 服務(wù)代理”。
ServiceAgent 類
Offline Application Block 提供了一個(gè) ServiceAgent 類。這個(gè)基類抽象了所有“應(yīng)用程序服務(wù)代理”的常見(jiàn)行為和數(shù)據(jù)。
ServiceAgent 基類最重要的責(zé)任是向 ServiceAgentRegistry 注冊(cè)“應(yīng)用程序服務(wù)代理”的所有實(shí)例。(該過(guò)程在抽象后置于 Service Agent 基類中,以增加代碼的可重復(fù)使用性。)“服務(wù)代理注冊(cè)表”用于在消息處理過(guò)程中,將事務(wù)的成功或失敗消息返回到原始的“應(yīng)用程序服務(wù)代理”。對(duì)基類的構(gòu)造函數(shù)中的所有派生類透明地完成該注冊(cè)。
類成員
以下部分(“屬性”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請(qǐng)參閱該應(yīng)用程序塊隨附的幫助文件。
屬性
GUID – ServiceAgent 類的每個(gè)實(shí)例的全局唯一標(biāo)識(shí)符 (GUID)。GUID 可唯一標(biāo)識(shí) ServiceAgentRegistry 中的特定“應(yīng)用程序服務(wù)代理”。
FailsafeServiceAgent 類
Offline Application Block 的設(shè)計(jì)目標(biāo)是將“聯(lián)機(jī)代理”執(zhí)行的結(jié)果返回到原始的“應(yīng)用程序服務(wù)代理”(如果該原始“應(yīng)用程序服務(wù)代理”仍然存在)。原始代理可能不存在的原因有以下幾個(gè):
? |
應(yīng)用程序可能顯式地將其從系統(tǒng)中刪除。 |
? |
應(yīng)用程序可能被關(guān)閉然后重新開(kāi)啟。 |
一旦“應(yīng)用程序服務(wù)代理”被損壞,則來(lái)自“聯(lián)機(jī)代理”的所有錯(cuò)誤都會(huì)丟失,這是因?yàn)樵挤?wù)代理已不再接收它們。在某些情況下,這還會(huì)導(dǎo)致數(shù)據(jù)丟失。為防止出現(xiàn)這種情況,該應(yīng)用程序塊提供了 FailsafeServiceAgent。
FailsafeServiceAgent 類很常用,它是“聯(lián)機(jī)代理”執(zhí)行過(guò)程中處理錯(cuò)誤的最后手段。它并不是通過(guò)其正常返回錯(cuò)誤的默認(rèn)“服務(wù)代理”。如果發(fā)生了以下所有事件,則結(jié)果將被返回到 FailsafeServiceAgent:
? |
該應(yīng)用程序塊在 Executor 中執(zhí)行“聯(lián)機(jī)代理”。 |
? |
該“聯(lián)機(jī)代理”失敗。 |
? |
找不到原始的“應(yīng)用程序服務(wù)代理”。 |
為了使該返回機(jī)制正常工作,應(yīng)用程序必須滿足以下要求:
? |
只使用從 OfflineBlockBuilder 檢索的 FailsafeServiceAgent 的實(shí)例。 |
? |
始終維護(hù)在 FailsafeServiceAgent 類的 ErrorEvent 中注冊(cè)的回調(diào)方法。 |
ServiceAgentContext 類
當(dāng)“服務(wù)代理管理器”調(diào)用“應(yīng)用程序服務(wù)代理”的一個(gè)方法時(shí),會(huì)從 ServiceAgentContext 類中檢索要調(diào)用的相應(yīng)方法。Payload(在本章的“消息數(shù)據(jù)管理”部分中定義)可為每個(gè)請(qǐng)求提供“服務(wù)代理”上下文。
類成員
以下部分(“屬性”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請(qǐng)參閱該應(yīng)用程序塊隨附的幫助文件。
屬性
MethodToInvoke – 返回要調(diào)用的方法名稱。“服務(wù)代理管理器”調(diào)用“應(yīng)用程序服務(wù)代理”的這個(gè)方法,以傳回請(qǐng)求的結(jié)果。
OnlineProxyContext 類
OnlineProxyContext 類可封裝調(diào)用“聯(lián)機(jī)代理”的遠(yuǎn)程服務(wù)請(qǐng)求行為所必需的信息。Payload(在后面的“消息數(shù)據(jù)管理”部分中定義)可為每個(gè)請(qǐng)求提供“聯(lián)機(jī)代理”上下文。
ServiceAgentManager類
ServiceAgentManager 可將服務(wù)請(qǐng)求的結(jié)果返回到適當(dāng)?shù)摹皯?yīng)用程序服務(wù)代理”。代理是由其 GUID 識(shí)別的。ServiceAgentManager 使用 GUID 從“服務(wù)代理注冊(cè)表”中獲得特定“應(yīng)用程序服務(wù)代理”的實(shí)例 — 它會(huì)調(diào)用指定的“應(yīng)用程序服務(wù)代理”方法。每次實(shí)例化一個(gè)“應(yīng)用程序服務(wù)代理”,它就會(huì)得到一個(gè)新的 GUID。
ServiceAgentRegistry 類
ServiceAgentRegistry 類可作為當(dāng)前活動(dòng)的“應(yīng)用程序服務(wù)代理”的儲(chǔ)備庫(kù)。在創(chuàng)建“應(yīng)用程序服務(wù)代理”時(shí),會(huì)將它們添加到注冊(cè)表中。“服務(wù)代理管理器”根據(jù) GUID 來(lái)查找“應(yīng)用程序服務(wù)代理”。每個(gè) GUID 都表示一個(gè)實(shí)例化的“應(yīng)用程序服務(wù)代理”。
ThreadPoolInvoker 類
在處理請(qǐng)求后,“服務(wù)代理管理器”使用 ThreadPoolInvoker 類將結(jié)果傳回位于線程池線程上的“應(yīng)用程序服務(wù)代理”回調(diào)方法。
消息數(shù)據(jù)管理
“消息數(shù)據(jù)管理”子系統(tǒng)管理存儲(chǔ)在隊(duì)列中的事務(wù)性數(shù)據(jù),并提供將同步數(shù)據(jù)的功能添加到服務(wù)器的基礎(chǔ)結(jié)構(gòu)。該子系統(tǒng)由下列組件構(gòu)成:
? |
隊(duì)列消息 – QueueMessage 類是存儲(chǔ)在隊(duì)列中的消息的容器。 |
? |
隊(duì)列管理器 – QueueManager 是“消息數(shù)據(jù)管理”子系統(tǒng)的一個(gè)接口,它公開(kāi)了將消息添加到隊(duì)列以及從隊(duì)列中刪除消息的方法。 |
? |
Executor – Executor 類從隊(duì)列中檢索消息,然后將它們發(fā)送到處理該請(qǐng)求的適當(dāng)“聯(lián)機(jī)代理”。Executor 根據(jù) QueueMessage 中的可用信息使用反射來(lái)實(shí)例化“聯(lián)機(jī)代理”。 |
? |
隊(duì)列存儲(chǔ)提供程序 – 這些類抽象了與物理隊(duì)列存儲(chǔ)區(qū)的交互。該應(yīng)用程序塊附帶了用于 Microsoft 消息隊(duì)列 (MSMQ)、Microsoft SQL Server? 桌面引擎 (MSDE)、獨(dú)立的存儲(chǔ)區(qū)以及內(nèi)存的提供程序。 |
類設(shè)計(jì)
“消息數(shù)據(jù)管理”子系統(tǒng)支持異步處理與應(yīng)用程序相關(guān)的消息:
? |
提供一致的用戶體驗(yàn),無(wú)論是聯(lián)機(jī)狀態(tài)還是脫機(jī)狀態(tài)。無(wú)論連接狀態(tài)如何,“消息數(shù)據(jù)管理”都能夠排列要異步執(zhí)行的所有消息。當(dāng)應(yīng)用程序處于聯(lián)機(jī)狀態(tài)時(shí),就會(huì)執(zhí)行消息。 |
? |
避免阻塞運(yùn)行過(guò)程較長(zhǎng)的 UI 線程。 |
QueueMessage 類
QueueMessage 類是存儲(chǔ)在隊(duì)列中的數(shù)據(jù)的容器。Payload 是“隊(duì)列消息”攜帶的關(guān)鍵元素。開(kāi)發(fā)人員可以將 QueueMessage 類視作基類,并對(duì)其進(jìn)行擴(kuò)展以添加他們的應(yīng)用程序所需的任何附加功能。
類成員
以下部分(“屬性”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請(qǐng)參閱該應(yīng)用程序塊中隨附的幫助文件。
屬性
MessagePayload – 返回一個(gè)類型為 Payload 的對(duì)象。Payload 包含用于處理請(qǐng)求的數(shù)據(jù)。它還包括有關(guān)處理請(qǐng)求以及返回結(jié)果的組件的元數(shù)據(jù)。
QueueManager 類
QueueManager 類是“消息數(shù)據(jù)管理”子系統(tǒng)的一個(gè)接口,它具有以下功能:
? |
它是一個(gè)線程安全的組件,可以在多個(gè)線程上同時(shí)被訪問(wèn)。 |
? |
根據(jù)應(yīng)用程序的配置設(shè)置,它可以實(shí)例化適當(dāng)?shù)年?duì)列存儲(chǔ)提供程序(通過(guò)實(shí)現(xiàn) IQueueStorageProvider 接口)。 |
? |
它可以公開(kāi)在隊(duì)列中添加和刪除消息的方法。 |
為了保持消息的順序,Offline Application Block 可在“隊(duì)列管理器”中強(qiáng)制使用“先進(jìn)先出”(FIFO) 語(yǔ)義。
類成員
以下部分(“方法”和“屬性”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請(qǐng)參閱該應(yīng)用程序塊中隨附的幫助文件。
方法
? |
Enqueue – 將消息添加到隊(duì)列中。它可以接受類型為 Payload 的參數(shù)作為輸入。該方法將 Payload 輸入封裝在 QueueMessage 中,然后使用指定的隊(duì)列存儲(chǔ)提供程序?qū)⑵浯鎯?chǔ)在隊(duì)列中。 |
? |
Dequeue – 使用指定的隊(duì)列存儲(chǔ)提供程序從隊(duì)列中刪除和返回消息。 |
屬性
Size – 返回與隊(duì)列大小相對(duì)應(yīng)的 System.Int32 值。
Payload 類
Payload 類是處理一個(gè)消息所需的所有信息的數(shù)據(jù)容器。它包含:
? |
要調(diào)用的“聯(lián)機(jī)代理”方法的名稱。 |
? |
要發(fā)送到服務(wù)器的數(shù)據(jù)。 |
? |
從服務(wù)器接收的數(shù)據(jù)。 |
? |
應(yīng)接收返回?cái)?shù)據(jù)的“應(yīng)用程序服務(wù)代理”的標(biāo)識(shí)。 |
在大多數(shù)情況下,該類應(yīng)可以滿足任何開(kāi)發(fā)人員的要求,但是如有必要,可以擴(kuò)展它以包含其他消息數(shù)據(jù)。
類成員
以下部分(“方法”和“屬性”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請(qǐng)參閱該應(yīng)用程序塊中隨附的幫助文件。
方法
RecordFailure – Payload 類上公開(kāi)的方法,它可記錄在處理請(qǐng)求的過(guò)程中所發(fā)生的任何故障。該方法可接受 Exception 作為參數(shù),并為 Payload 類的這個(gè)實(shí)例設(shè)置 FailureReason 值。
屬性
? |
PayloadGuid – 為 Payload 類的每個(gè)實(shí)例生成的全局唯一標(biāo)識(shí)符 (GUID)。應(yīng)用程序可以使用此信息來(lái)關(guān)聯(lián)數(shù)據(jù);但應(yīng)用程序塊并沒(méi)有提供支持它的任何基礎(chǔ)結(jié)構(gòu)。 |
? |
ServiceAgentGuid – 為“應(yīng)用程序服務(wù)代理”的每個(gè)對(duì)象所生成的全局唯一標(biāo)識(shí)符 (GUID)。當(dāng)結(jié)果在處理后被傳回正確的“應(yīng)用程序服務(wù)代理”時(shí),在“服務(wù)代理管理器”中使用 GUID 從注冊(cè)表中檢索“應(yīng)用程序服務(wù)代理”。 |
? |
MethodToExecute – 包含調(diào)用特定聯(lián)機(jī)代理方法的 OnlineProxyContext 的實(shí)例。 |
? |
ResultCallbackTarget – 包含將結(jié)果返回到“應(yīng)用程序服務(wù)代理”的 ServiceAgentContext 的實(shí)例。 |
? |
RequestData – 包含處理創(chuàng)建 Payload 的請(qǐng)求所必需的數(shù)據(jù)。它由創(chuàng)建 Payload 的“服務(wù)代理”填充。 |
? |
Results – 包含處理請(qǐng)求的結(jié)果。它由與服務(wù)進(jìn)行通信的“聯(lián)機(jī)代理”填充。 |
? |
FailureReason – 返回一個(gè)類型為 System.Exception 的對(duì)象,該對(duì)象包含由于處理請(qǐng)求中的故障而產(chǎn)生的異常。 |
? |
Success – 返回一個(gè)布爾值,表示請(qǐng)求處理是否成功。 |
Executor 類
Executor 類從隊(duì)列中檢索消息。它運(yùn)行在自己的線程上,每秒輪詢一次隊(duì)列以檢查是否有新消息,并持續(xù)處理消息直到隊(duì)列為空。然后,它在再次檢查是否存在可用消息前停止 1 秒鐘。從隊(duì)列中檢索一個(gè)消息后,Executor 會(huì)調(diào)用實(shí)現(xiàn) ICommandProcessor 接口的類的實(shí)例上的方法,來(lái)執(zhí)行該消息。
SimpleCommandProcessor 類
SimpleCommandProcessor 類實(shí)現(xiàn) ICommandProcessor 接口,并通過(guò)實(shí)例化適當(dāng)?shù)摹奥?lián)機(jī)代理”并將結(jié)果返回到指定的結(jié)果回調(diào)目標(biāo),來(lái)使用反射執(zhí)行消息。該應(yīng)用程序塊將 ServiceAgentManager 用作返回結(jié)果的默認(rèn)目標(biāo)。
IQueueStorageProvider 接口
使用隊(duì)列存儲(chǔ)提供程序,可以將消息數(shù)據(jù)存儲(chǔ)在幾種不同類型的物理存儲(chǔ)區(qū)中。每個(gè)隊(duì)列存儲(chǔ)提供程序都必須實(shí)現(xiàn) IQueueStorageProvider 接口,才能用于應(yīng)用程序塊。QueueManagerBuilder 類可實(shí)例化隊(duì)列存儲(chǔ)提供程序,并將其傳遞到 QueueManager。
通過(guò)實(shí)現(xiàn)這個(gè)接口并在應(yīng)用程序配置文件中指定必要的配置信息,應(yīng)用程序開(kāi)發(fā)人員可以創(chuàng)建他們自己的隊(duì)列存儲(chǔ)提供程序。
盡管在配置文件中可以定義多個(gè)提供程序,但是在配置文件中只應(yīng)該啟用其中一個(gè)提供程序。如果配置文件中的提供程序發(fā)生更改,則該應(yīng)用程序塊將其視為用于存儲(chǔ)消息數(shù)據(jù)的新提供程序。該應(yīng)用程序塊沒(méi)有將數(shù)據(jù)從以前的存儲(chǔ)區(qū)移到新存儲(chǔ)區(qū)的內(nèi)置功能。
該應(yīng)用程序塊附帶四個(gè)隊(duì)列存儲(chǔ)提供程序:
? |
In Memory – 該提供程序在 InMemoryQueueStorageProvider 類中實(shí)現(xiàn)。它將隊(duì)列數(shù)據(jù)存儲(chǔ)在一個(gè)內(nèi)存數(shù)據(jù)結(jié)構(gòu) (System.Collection.Queue) 中。當(dāng)應(yīng)用程序重新啟動(dòng)時(shí),所存儲(chǔ)的數(shù)據(jù)將會(huì)丟失。不建議使用該提供程序存儲(chǔ)持久性數(shù)據(jù)。 |
? |
Isolated Storage – 該提供程序在 IsolatedStorageQueueStorageProvider 類中實(shí)現(xiàn)。它將隊(duì)列數(shù)據(jù)存儲(chǔ)到獨(dú)立存儲(chǔ)區(qū)中。建議使用該提供程序存儲(chǔ)持久性數(shù)據(jù)。 |
? |
MSDE – 該提供程序在 msdeQueueStorageProvider 類中實(shí)現(xiàn)。它將隊(duì)列數(shù)據(jù)存儲(chǔ)在 MSDE 中。建議使用該提供程序存儲(chǔ)持久性數(shù)據(jù)。 |
? |
MSMQ – 該提供程序在 msmqQueueStorageProvider 類中實(shí)現(xiàn)。它將隊(duì)列數(shù)據(jù)存儲(chǔ)在“消息隊(duì)列”中。該提供程序的自定義屬性位于配置文件中,并且可以定義隊(duì)列的名稱。建議使用該提供程序存儲(chǔ)持久性數(shù)據(jù)。 |
參考數(shù)據(jù)管理
即使處于脫機(jī)狀態(tài),智能客戶端應(yīng)用程序也必須為用戶提供他們繼續(xù)工作所需的數(shù)據(jù)。此數(shù)據(jù)通常稱為參考數(shù)據(jù),它在本地進(jìn)行緩存,并且在數(shù)據(jù)過(guò)期變舊時(shí)會(huì)進(jìn)行周期刷新。
參考數(shù)據(jù)通常是靜態(tài)的,但有時(shí)也可能被應(yīng)用程序更改。當(dāng)出現(xiàn)這種情況時(shí),Offline Application Block 會(huì)將數(shù)據(jù)標(biāo)記為 dirty。這樣會(huì)防止應(yīng)用程序塊在數(shù)據(jù)過(guò)期時(shí)刷新數(shù)據(jù),并且可以避免來(lái)自其他源的舊值覆寫已更新的數(shù)據(jù)。在更新與遠(yuǎn)程服務(wù)進(jìn)行同步后,數(shù)據(jù)被標(biāo)記為 clean,并且可以進(jìn)行刷新。
“參考數(shù)據(jù)管理”子系統(tǒng)可為應(yīng)用程序提供基礎(chǔ)結(jié)構(gòu),用于在本地緩存數(shù)據(jù)并在數(shù)據(jù)變舊時(shí)刷新數(shù)據(jù)。通過(guò)允許加密和解密緩存的數(shù)據(jù),它還提供了安全存儲(chǔ)數(shù)據(jù)的能力。
該子系統(tǒng)使用 Caching Application Block,它由下列組件構(gòu)成:
? |
ReferenceDataCache – Offline Application Block 通過(guò)該封裝程序公開(kāi)帶有支持聯(lián)機(jī)/脫機(jī)方案附加功能的緩存行為。 |
? |
ReferenceDataDefinition – 與參考緩存中的項(xiàng)目相關(guān)聯(lián)的元數(shù)據(jù)。它控制信息的刷新方式、信息何時(shí)過(guò)期以及維護(hù)數(shù)據(jù)的 dirty 和 clean 狀態(tài)標(biāo)記。 |
? |
ReferenceDataRefreshController – 當(dāng)某個(gè)項(xiàng)目過(guò)期時(shí),該類負(fù)責(zé)將該項(xiàng)目添加回緩存。它與 DataLoaderManager 協(xié)作來(lái)刷新緩存項(xiàng)目。 |
? |
DataLoaderManager – 該類可創(chuàng)建 ReferenceCacheDataPayload 并將消息添加到隊(duì)列中,以便下載參考數(shù)據(jù)并將其存儲(chǔ)到緩存中。 |
? |
ReferenceCacheDataPayload – 該類可利用對(duì) ReferenceDataDefinition(包含更新參考緩存數(shù)據(jù)所必需的元數(shù)據(jù))的參考,來(lái)擴(kuò)展 Payload 類。 |
有關(guān)“參考數(shù)據(jù)管理”子系統(tǒng)如何工作的進(jìn)一步說(shuō)明,請(qǐng)參閱本章的“參考數(shù)據(jù)緩存工作流”部分。
類設(shè)計(jì)
“參考數(shù)據(jù)管理”子系統(tǒng)提供了用于管理處理緩存、存儲(chǔ)和刷新數(shù)據(jù)的組件的類。
ReferenceDataCache 類
該應(yīng)用程序塊通過(guò)該封裝程序公開(kāi)帶有支持脫機(jī)和聯(lián)機(jī)方案附加功能的緩存行為。該類實(shí)現(xiàn) IReferenceDataCache,并且該類的客戶端應(yīng)訪問(wèn)這種類型的對(duì)象。
類成員
以下部分(“方法”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請(qǐng)參閱該應(yīng)用程序塊中隨附的幫助文件。
方法
? |
Store – 使用指定的緩存項(xiàng)來(lái)存儲(chǔ)參考緩存數(shù)據(jù)項(xiàng)目。Store 不要求緩存中存在項(xiàng)目。 |
? |
Update – 在緩存項(xiàng)指定的位置更新參考緩存數(shù)據(jù)項(xiàng)目。Update 要求緩存中存在項(xiàng)目。 |
? |
Retrieve – 對(duì)于給定的緩存項(xiàng),檢索參考緩存數(shù)據(jù)項(xiàng)目。 |
? |
Remove – 對(duì)于給定的緩存項(xiàng),刪除參考緩存數(shù)據(jù)項(xiàng)目。 |
? |
IsDirty – 返回一個(gè)布爾值,表示位于指定緩存項(xiàng)位置的項(xiàng)目是否已由應(yīng)用程序修改。 |
? |
MarkAsClean – 如果參考數(shù)據(jù)緩存項(xiàng)目存在于緩存中,它會(huì)將該項(xiàng)目標(biāo)記為 clean。這表示作為工作流(在指定的緩存項(xiàng)位置修改參考數(shù)據(jù)項(xiàng)目)一部分而生成的消息已經(jīng)進(jìn)行了處理。 |
? |
ItemHasBeenExpired – 用于將項(xiàng)目標(biāo)記為“已過(guò)期”的方法。 |
ReferenceDataDefinition 類
該類包含與參考緩存中的項(xiàng)目相關(guān)聯(lián)的元數(shù)據(jù)。它控制信息的刷新方式、信息何時(shí)過(guò)期以及維護(hù)數(shù)據(jù)的 dirty 和 clean 狀態(tài)標(biāo)記。
ReferenceDataRefreshController 類
當(dāng)某個(gè)項(xiàng)目過(guò)期時(shí),該類負(fù)責(zé)將該項(xiàng)目添加回緩存。它與 DataLoaderManager 協(xié)作來(lái)刷新隊(duì)列。
該功能必須作為獨(dú)立的類存在,而不是嵌入到 ReferenceDataCache 本身中,它促進(jìn)了應(yīng)用程序塊中各個(gè)元素之間的松散耦合。使 ReferenceDataCache 依賴于 DataLoaderManager 會(huì)不必要地耦合這兩個(gè)子系統(tǒng)。通過(guò)將該責(zé)任轉(zhuǎn)移給第三類,可以消除這種依存關(guān)系,并可以使整個(gè)應(yīng)用程序塊保持松散耦合。為了正常工作,該類需要訪問(wèn) ReferenceDataCache 和 DataLoaderManager。
DataLoaderManager 類
該類負(fù)責(zé)下載參考數(shù)據(jù)。為此,它將創(chuàng)建 ReferenceCacheDataPayload 并將其添加到隊(duì)列中,以便可以處理消息和下載參考數(shù)據(jù)。下載的參考數(shù)據(jù)存儲(chǔ)在緩存中。
類成員
以下部分(“方法”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請(qǐng)參閱該應(yīng)用程序塊中隨附的幫助文件。
方法
? |
LoadData – 創(chuàng)建 ReferenceCacheDataPayload 并將其排入隊(duì)列以便異步處理,來(lái)開(kāi)始下載參考數(shù)據(jù)。 |
? |
RefreshData – 創(chuàng)建 ReferenceCacheDataPayload 并將其排入隊(duì)列以便異步處理,來(lái)刷新參考數(shù)據(jù)緩存中的過(guò)期數(shù)據(jù)。 |
ReferenceCacheDataPayload 類
該類派生自 Payload 類,同時(shí)也包含 ReferenceDataDefinition。該組件是有關(guān)更新參考緩存數(shù)據(jù)所需的參考數(shù)據(jù)的元數(shù)據(jù)。
類成員
以下部分(“方法”和“屬性”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請(qǐng)參閱該應(yīng)用程序塊中隨附的幫助文件。
方法
UpdateDataToReturn – 更新 Payload 中從遠(yuǎn)程服務(wù)返回的數(shù)據(jù)。
屬性
? |
DataDefinition – 返回來(lái)自創(chuàng)建 Payload 的參考數(shù)據(jù)緩存項(xiàng)目的 ReferenceDataDefinition 值。 |
? |
IsRefreshMessage – 布爾值,表示是否已創(chuàng)建 Payload 來(lái)刷新參考數(shù)據(jù)項(xiàng)目。 |
緩存塊和存儲(chǔ)提供程序
“參考數(shù)據(jù)管理”子系統(tǒng)使用 Caching Application Block 來(lái)存儲(chǔ)緩存的數(shù)據(jù)。緩存塊支持在配置文件中定義多個(gè)提供程序,但在配置文件中只能啟用其中一個(gè)提供程序。
如果配置文件中的提供程序發(fā)生更改,則該緩存塊將使用新的提供程序來(lái)存儲(chǔ)緩存數(shù)據(jù)。該塊沒(méi)有將數(shù)據(jù)從以前的數(shù)據(jù)存儲(chǔ)區(qū)移到新數(shù)據(jù)存儲(chǔ)區(qū)的內(nèi)置功能。這個(gè)功能必須由開(kāi)發(fā)人員添加。
除了 Caching Application Block 附帶的提供程序之外,Offline Application Block 還包括一個(gè)獨(dú)立的存儲(chǔ)緩存提供程序。這些提供程序的說(shuō)明如下:
? |
IsolatedStorageCacheProvider – 將緩存數(shù)據(jù)存儲(chǔ)在支持 .NET 的獨(dú)立存儲(chǔ)區(qū)中。當(dāng)項(xiàng)目被物理持久保存時(shí),它針對(duì)每個(gè)緩存項(xiàng)目使用一個(gè)文件。文件的名稱對(duì)應(yīng)于用戶指定的緩存項(xiàng)。在 Offline Application Block 中,緩存項(xiàng)將用作文件名,這就為緩存項(xiàng)創(chuàng)建了一個(gè)約束:緩存項(xiàng)不能包含被文件系統(tǒng)特殊處理的符號(hào),例如,“\”、“*”或“?”。該塊可確保應(yīng)用程序開(kāi)發(fā)人員所使用的任何項(xiàng)目名稱都對(duì)應(yīng)于“獨(dú)立存儲(chǔ)”中的有效文件名,否則它將引發(fā)一個(gè)異常。 |
? |
Caching Application Block Providers – 包括用于 SQL Server、內(nèi)存存儲(chǔ)和內(nèi)存映射文件存儲(chǔ)的緩存存儲(chǔ)提供程序。有關(guān)詳細(xì)信息,請(qǐng)參閱 Caching Application Block。 |
實(shí)用工具服務(wù)
“實(shí)用工具服務(wù)”提供后臺(tái)服務(wù),例如多提供程序配置處理程序、配置程序和生成器。生成器用于創(chuàng)建特定類的實(shí)例。生成器使用配置程序從配置文件中讀取相關(guān)信息。
MultiProviderConfigHandler 類
Offline Application Block 提供為配置文件中的單個(gè)配置區(qū)段定義多個(gè)提供程序的能力。當(dāng)您管理多個(gè)類型的數(shù)據(jù)存儲(chǔ)區(qū)并需要關(guān)聯(lián)來(lái)自這些不同數(shù)據(jù)存儲(chǔ)區(qū)的數(shù)據(jù)時(shí),多個(gè)提供程序非常有用。在這種情況下,您需要通過(guò)編程手段在讀取數(shù)據(jù)和關(guān)聯(lián)數(shù)據(jù)時(shí)逐個(gè)啟用或禁用存儲(chǔ)區(qū)。這些區(qū)段中只有一個(gè)必須通過(guò)將 enabled 屬性設(shè)置為 true 來(lái)啟用。MultiProviderConfigHandler 類負(fù)責(zé)讀取配置信息,并確保滿足該條件。它實(shí)現(xiàn)接口 IConfigurationSectionHandler,并實(shí)現(xiàn)該接口強(qiáng)制的 Create 方法。
類成員
以下部分(“方法”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請(qǐng)參閱該應(yīng)用程序塊中隨附的幫助文件。
方法
Create – 從配置文件 (App.config) 中讀取指定配置區(qū)段,并返回該類的客戶端可以使用的 System.Collections.Hashtable 中的信息。
如果您計(jì)劃在設(shè)計(jì)中使用多個(gè)提供程序,則使用該類可以簡(jiǎn)化您的代碼。
生成器
該應(yīng)用程序塊中的每個(gè)關(guān)鍵類都具有一個(gè)關(guān)聯(lián)的生成器類。生成器類抽象了從生成器類的客戶端創(chuàng)建關(guān)聯(lián)類的實(shí)例的復(fù)雜性。每個(gè)生成器類都使用 Builder 模式。
對(duì)于諸如 ConnectionManager、DataLoaderManager、ServiceAgentManager、QueueManager、Executor、ReferenceDataCache 和 DataLoaderManager 這樣的類,整個(gè)應(yīng)用程序只需要一個(gè)類的實(shí)例,因此可以將這些類創(chuàng)建為 Singleton。但是,Singleton 具有一個(gè)缺點(diǎn),那就是會(huì)導(dǎo)致強(qiáng)耦合。這一點(diǎn)抑制了塊體系結(jié)構(gòu)的優(yōu)點(diǎn),從而鼓勵(lì)了可交互、可重復(fù)使用的代碼的開(kāi)發(fā),這些代碼的類可單獨(dú)進(jìn)行測(cè)試。包含生成器類的目的在于創(chuàng)建特定類的實(shí)例,而不是使用 Singleton。
OfflineBlockBuilder
OfflineBlockBuilder 類是應(yīng)用程序開(kāi)發(fā)人員需要調(diào)用以實(shí)例化所有子系統(tǒng)的唯一類。它通過(guò)調(diào)用相應(yīng)的生成器類來(lái)完成。它是 Singleton,您可以使用該類的 Instance 屬性來(lái)訪問(wèn)它。它將所有關(guān)鍵類公開(kāi)為屬性。下面的列表包含了由 OfflineBlockBuilder 類創(chuàng)建的所有類:
? |
DataLoaderManager |
? |
ReferenceDataCache |
? |
ServiceAgentManager |
? |
ServiceAgentRegistry |
? |
ConnectionManager |
? |
PayloadConsumer(隊(duì)列所公開(kāi)的接口,用于支持向隊(duì)列中添加項(xiàng)目所需的功能) |
OfflineBlockBuilder 類還支持啟動(dòng)和停止所有子系統(tǒng)的 Start 和 Stop 方法。下面列出的是該類中最重要的成員。有關(guān)詳細(xì)信息,請(qǐng)參閱該應(yīng)用程序塊中隨附的幫助文件。
? |
Instance – 創(chuàng)建塊生成器的實(shí)例。 |
? |
Start – 啟動(dòng)塊。 |
? |
Stop – 停止塊。 |
? |
Dispose – 停止塊并處理 OfflineBlockBuilder。 |
ConnectionManagerBuilder 類
ConnectionManagerBuilder 類可構(gòu)建 ConnectionManager 類并將 ConnectionManager 作為一個(gè)屬性公開(kāi)。
ServiceAgentManagerBuilder 類
ServiceAgentManagerBuilder 類可構(gòu)建 ServiceAgentManager 類并將 ServiceAgentManager 作為一個(gè)屬性公開(kāi)。此外,它還可以創(chuàng)建 ServiceAgentRegistry 類的一個(gè)對(duì)象,并將其作為一個(gè)屬性公開(kāi)。
QueueManagerBuilder 類
QueueManagerBuilder 類可構(gòu)建 QueueManager 類并將 QueueManager 作為一個(gè)屬性公開(kāi)。通過(guò)使用 QueueManagerConfigurator 類,該類可以從配置文件中獲得隊(duì)列存儲(chǔ)提供程序的信息。它可創(chuàng)建在配置文件中指定的隊(duì)列存儲(chǔ)提供程序的實(shí)例,并在創(chuàng)建過(guò)程中將其傳遞到 QueueManager。
ExecutorBuilder 類
ExecutorBuilder 類可構(gòu)建 Executor 類并將 Executor 作為一個(gè)屬性公開(kāi)。
ReferenceDataCacheBuilder 類
ReferenceDataCacheBuilder 類可構(gòu)建 IReferenceDataCache 接口類型,并將 IReferenceDataCache 類型對(duì)象作為一個(gè)屬性公開(kāi)。
DataLoaderManagerBuilder 類
DataLoaderManagerBuilder 類可構(gòu)建 DataLoaderManager 類并將 DataLoaderManager 作為一個(gè)屬性公開(kāi)。
參考數(shù)據(jù)緩存工作流
本部分介紹使用 Offline Application Block 來(lái)下載、管理、刷新和緩存參考數(shù)據(jù)的工作流。
下載參考緩存數(shù)據(jù)
如前所述,若要使應(yīng)用程序在脫機(jī)狀態(tài)下工作,必須下載參考數(shù)據(jù)并將其緩存到客戶端上。下載參考數(shù)據(jù)是由應(yīng)用程序啟動(dòng)的。根據(jù)連接狀態(tài),應(yīng)用程序可以決定是否啟動(dòng)下載參考數(shù)據(jù)項(xiàng)目。在這方面,應(yīng)用程序塊不會(huì)強(qiáng)制執(zhí)行任何操作。
協(xié)作下載參考數(shù)據(jù)的組件包括由應(yīng)用程序開(kāi)發(fā)人員創(chuàng)建的“應(yīng)用程序服務(wù)代理”、應(yīng)用程序塊中提供的 DataLoaderManager 類以及“消息數(shù)據(jù)管理”子系統(tǒng)。下列步驟演練了圖 2.6 中所示的過(guò)程。
應(yīng)用程序創(chuàng)建“應(yīng)用程序服務(wù)代理”的一個(gè)實(shí)例。“應(yīng)用程序服務(wù)代理”為參考緩存數(shù)據(jù)項(xiàng)目創(chuàng)建一個(gè) ReferenceDataDefinition 對(duì)象。“應(yīng)用程序服務(wù)代理”指定與緩存項(xiàng)目相對(duì)應(yīng)的項(xiàng)、可選的過(guò)期策略以及 OnlineProxyContext 和 ServiceAgentContext。 “服務(wù)代理”實(shí)例化 DataLoaderManager,并為它提供對(duì)應(yīng)于需要下載的參考緩存數(shù)據(jù)項(xiàng)目的 ReferenceDataDefinition。 DataLoaderManager 使用 ReferenceDataDefinition 創(chuàng)建 ReferenceCacheDataPayload 的一個(gè)實(shí)例,并使用“信息數(shù)據(jù)管理”子系統(tǒng)將其排入隊(duì)列以進(jìn)行異步處理。 “消息數(shù)據(jù)管理”子系統(tǒng)的消息處理會(huì)導(dǎo)致從遠(yuǎn)程服務(wù)檢索參考緩存數(shù)據(jù)項(xiàng)目。“聯(lián)機(jī)代理”將參考數(shù)據(jù)添加到參考緩存中。 結(jié)果被返回給特定的“應(yīng)用程序服務(wù)代理”。
圖 2.6.排隊(duì)參考數(shù)據(jù)加載請(qǐng)求
刷新參考緩存數(shù)據(jù)
下載的參考緩存數(shù)據(jù)會(huì)在一段時(shí)間后變舊。該應(yīng)用程序塊可提供為每個(gè)參考緩存數(shù)據(jù)項(xiàng)目指定過(guò)期策略的功能。根據(jù)該過(guò)期策略,應(yīng)用程序塊可刷新參考緩存數(shù)據(jù)項(xiàng)目。當(dāng)參考緩存數(shù)據(jù)項(xiàng)目過(guò)期后,該應(yīng)用程序塊會(huì)根據(jù) Caching Application Block 的 CacheManager 組件引發(fā)的事件來(lái)啟動(dòng)刷新。
協(xié)作刷新參考緩存數(shù)據(jù)的組件包括 CacheManager、ReferenceDataCache、ReferenceDataRefreshController 和 DataLoaderManager。
當(dāng)參考緩存數(shù)據(jù)項(xiàng)目下載并添加到緩存中時(shí),如前一部分“下載參考緩存數(shù)據(jù)”中的說(shuō)明,您可以在參考數(shù)據(jù)定義中為緩存項(xiàng)目指定過(guò)期策略。除此之外,當(dāng)某個(gè)項(xiàng)目過(guò)期時(shí),Caching Application Block 還允許指定回調(diào)方法(委派)。當(dāng)參考緩存數(shù)據(jù)項(xiàng)目存儲(chǔ)在緩存中時(shí),如果項(xiàng)目過(guò)期,ReferenceDataRefreshController 類的 CacheItemExpiredCallback 方法被指定為回調(diào)方法。圖 2.7 展示了說(shuō)明下列步驟的過(guò)程:
? |
CacheManager 監(jiān)視緩存項(xiàng)目是否過(guò)期。當(dāng)某個(gè)項(xiàng)目過(guò)期時(shí),緩存管理器將調(diào)用的 ReferenceDataRefreshController 的指定 CacheItemExpiredCallback 方法。 |
? |
如果緩存項(xiàng)目已經(jīng)過(guò)期,則基礎(chǔ) Caching Application Block 將從緩存中刪除該項(xiàng)目。在啟動(dòng)下載前,ReferenceDataRefreshController 將該項(xiàng)目添加回緩存中 — 這樣做可防止信息丟失。 |
? |
然后,ReferenceDataRefreshController 通過(guò) DataLoaderManager 來(lái)啟動(dòng)下載參考數(shù)據(jù)項(xiàng)目。 |
? |
DataLoaderManager 使用 ReferenceDataDefinition 來(lái)創(chuàng)建 ReferenceCacheDataPayload 的實(shí)例。然后,它使用“消息數(shù)據(jù)管理”子系統(tǒng)的類 QueueManager 將 ReferenceCacheDataPayload 的對(duì)象作為消息排入隊(duì)列以進(jìn)行異步處理。 |
? |
“消息數(shù)據(jù)管理”子系統(tǒng)的消息處理會(huì)導(dǎo)致從遠(yuǎn)程服務(wù)檢索參考緩存數(shù)據(jù)項(xiàng)目。“聯(lián)機(jī)代理”將參考數(shù)據(jù)添加到參考緩存中。 |
? |
結(jié)果被返回給特定的“應(yīng)用程序服務(wù)代理”。 |
圖 2.7.緩存項(xiàng)目過(guò)期并獲得刷新
根據(jù)設(shè)計(jì),在“參考數(shù)據(jù)緩存”中刷新參考數(shù)據(jù)時(shí),Offline Application Block 不會(huì)將事件提交到應(yīng)用程序。如下面的說(shuō)明所示,添加該功能是一項(xiàng)簡(jiǎn)單的任務(wù)。
當(dāng)完成服務(wù)請(qǐng)求以及當(dāng)(且僅當(dāng))相同的“服務(wù)代理”可以由 Offline Application Block 回調(diào)時(shí),請(qǐng)記住將事件提交到應(yīng)用程序。如果在刷新緩存中的數(shù)據(jù)時(shí)發(fā)生相同的情況,則必須創(chuàng)建一個(gè)長(zhǎng)期的“服務(wù)代理”并在每次刷新數(shù)據(jù)時(shí)使用,而且還必須使該“服務(wù)代理”可用于該應(yīng)用程序,以便它可以注冊(cè)接收這些完成事件。該實(shí)現(xiàn)類似于 FailsafeServiceAgent 實(shí)現(xiàn)。
管理參考緩存數(shù)據(jù)
要管理參考緩存數(shù)據(jù),您必須以某種方式對(duì)其進(jìn)行標(biāo)記,以便知道該數(shù)據(jù)是否需要刷新。數(shù)據(jù)可以標(biāo)記為 dirty、expired 或者兩者。根據(jù)標(biāo)記數(shù)據(jù)的方式,參考緩存處理數(shù)據(jù)的方式可能會(huì)更改。
如果數(shù)據(jù)為 dirty,則意味著它已經(jīng)在本地進(jìn)行更改,但沒(méi)有在服務(wù)器上進(jìn)行更改。一旦在服務(wù)器上進(jìn)行更新,數(shù)據(jù)會(huì)標(biāo)記為 clean。請(qǐng)記住,我們沒(méi)有辦法知道消息何時(shí)在服務(wù)器上進(jìn)行實(shí)際更新。它也可能在計(jì)劃批作業(yè)完成之后發(fā)生。同樣,如果數(shù)據(jù)更改過(guò)幾次,則直到發(fā)送所有更新請(qǐng)求之后,它才會(huì)標(biāo)記為 clean。
數(shù)據(jù)還可以在參考緩存中標(biāo)記為 expired。這意味著“緩存管理器”已經(jīng)確定緩存中的某個(gè)項(xiàng)目已經(jīng)過(guò)期,導(dǎo)致“緩存管理器”將其從緩存中刪除并對(duì)有關(guān)該過(guò)期項(xiàng)目的參考數(shù)據(jù)執(zhí)行一個(gè)回調(diào)方法。
理解參考緩存中的“臟”(dirty) 數(shù)據(jù)如何與“過(guò)期”(expired) 數(shù)據(jù)進(jìn)行交互非常重要。
? |
既不是“臟”又不是“過(guò)期”的數(shù)據(jù)被視為干凈的數(shù)據(jù)。如果該數(shù)據(jù)過(guò)期,它就會(huì)被刷新。 |
? |
如果已標(biāo)記為 expired 的數(shù)據(jù)再次過(guò)期,將不會(huì)為其執(zhí)行另一次刷新操作。 |
? |
如果數(shù)據(jù)過(guò)期且標(biāo)記為 dirty,則在參考緩存中將數(shù)據(jù)標(biāo)記為 clean 之前,將不會(huì)刷新該數(shù)據(jù)。原因是,使數(shù)據(jù)在本地變臟的操作為數(shù)據(jù)提供了比刷新后的數(shù)據(jù)更好、更新的值。因此,刷新消息的結(jié)果可以忽略。 |
緩存參考數(shù)據(jù)
Caching Application Block 允許您為緩存的項(xiàng)目指定特定的元數(shù)據(jù)。這包括過(guò)期策略以及當(dāng)項(xiàng)目過(guò)期時(shí)的回調(diào)方法。Offline Application Block 必須支持其他元數(shù)據(jù),才能指定組件的上下文信息。當(dāng)某個(gè)項(xiàng)目過(guò)期時(shí),這些組件會(huì)檢索參考數(shù)據(jù)。創(chuàng)建 ReferenceDataDefinition 類以存儲(chǔ)擴(kuò)展的元數(shù)據(jù)。ReferenceDataDefinition 類還包含一個(gè)到實(shí)際參考緩存項(xiàng)目的項(xiàng)。除了在需要時(shí)傳遞該信息的能力外,當(dāng)您需要檢查有關(guān)參考緩存項(xiàng)目的元數(shù)據(jù)時(shí),它還提供了一個(gè)優(yōu)化,這是因?yàn)椴恍枰葱蛄谢麄€(gè)緩存項(xiàng)目。
當(dāng)某個(gè)項(xiàng)目過(guò)期時(shí),Caching Application Block 會(huì)在通知應(yīng)用程序之前從緩存中永久性的刪除該項(xiàng)目。這對(duì)于以脫機(jī)模式運(yùn)行的應(yīng)用程序來(lái)說(shuō)有幾個(gè)含義。如果刪除了緩存的項(xiàng)目,應(yīng)用程序就無(wú)法使用緩存中的數(shù)據(jù)來(lái)繼續(xù)操作。由于 ReferenceDataDefinition 和緩存項(xiàng)目都被緩存,如果它們兩者都從緩存中被刪除,就無(wú)法檢索它們并將它們添加回參考緩存數(shù)據(jù)中。要克服這一限制,可以在緩存的存儲(chǔ)架構(gòu)中添加一個(gè)間接層。
使用該架構(gòu),過(guò)期在第一個(gè)間接層上指定。當(dāng)該項(xiàng)目過(guò)期時(shí),將出現(xiàn)一個(gè)帶有該項(xiàng)的值的通知。然后,為 ReferenceDataDefinition 和參考緩存項(xiàng)目自動(dòng)生成項(xiàng)。這樣,應(yīng)用程序就可以繼續(xù)訪問(wèn)它們。ReferenceDataRefreshController 接收通知并使用 DataLoaderManager 來(lái)刷新數(shù)據(jù)。DataLoaderManager 組件在開(kāi)始下載前添加第一級(jí)架構(gòu)。
Caching Application Block 已經(jīng)提供了內(nèi)存緩存、內(nèi)存映射文件緩存以及 SQL 數(shù)據(jù)庫(kù)緩存。Offline Application Block 構(gòu)建在該基礎(chǔ)結(jié)構(gòu)上,通過(guò)包括獨(dú)立存儲(chǔ)緩存提供程序來(lái)提供緩存支持。該提供程序允許應(yīng)用程序?qū)⑻囟ㄓ诓煌脩舻臄?shù)據(jù)存儲(chǔ)在運(yùn)行智能客戶端應(yīng)用程序的客戶端計(jì)算機(jī)上的不同位置。
Caching Application Block 支持對(duì)緩存數(shù)據(jù)進(jìn)行加密和解密。Offline Application Block 利用該功能根據(jù)配置信息來(lái)確保緩存數(shù)據(jù)的安全。
請(qǐng)求和響應(yīng)往返
本部分說(shuō)明了在使用 Offline Application Block 的應(yīng)用程序中,請(qǐng)求和響應(yīng)的往返過(guò)程是如何實(shí)現(xiàn)的。下列步驟說(shuō)明了圖 2.8 中闡釋的往返行程。
? |
應(yīng)用程序的“用戶界面控制器”(UIC) 通常會(huì)創(chuàng)建一個(gè)執(zhí)行該任務(wù)的特定“應(yīng)用程序服務(wù)代理”的實(shí)例。“應(yīng)用程序服務(wù)代理”將創(chuàng)建 Payload 以便執(zhí)行該任務(wù)。Payload 包含執(zhí)行該任務(wù)所需的所有數(shù)據(jù)。此外,Payload 還包含有關(guān) OnlineProxyContext 和 ServiceAgentContext 中組件的所有上下文信息。 |
? |
使用 QueueManager 類的 Enqueue 方法,“應(yīng)用程序服務(wù)代理”可將 Payload 排入隊(duì)列。在使用已配置的隊(duì)列存儲(chǔ)提供程序?qū)?Payload 存儲(chǔ)到隊(duì)列之前,Enqueue 方法將 Payload 封裝在 QueueMessage 類中。 |
? |
如果應(yīng)用程序處于聯(lián)機(jī)狀態(tài),Executor(運(yùn)行在獨(dú)立線程上)將使用 QueueManager 類的 Dequeue 方法從隊(duì)列中獲取 QueueMessage。然后,它從 QueueMessage 中檢索 Payload。 |
? |
Executor 從對(duì)應(yīng)于“聯(lián)機(jī)狀態(tài)”的 Payload 中檢索 OnlineProxyContext。通過(guò)反射使用 OnlineProxyContext 信息,它可執(zhí)行指定的“聯(lián)機(jī)代理”方法。“聯(lián)機(jī)代理”與遠(yuǎn)程服務(wù)進(jìn)行交互以完成該操作。“聯(lián)機(jī)代理”還將緩存結(jié)果、執(zhí)行所有請(qǐng)求后期處理,并處理公共事務(wù)。 |
? |
在執(zhí)行請(qǐng)求后,“聯(lián)機(jī)代理”將結(jié)果填充到 Payload 中。然后,Executor 將 Payload 返回到 ServiceAgentManager。 |
? |
ServiceAgentManager 類從 Payload 中檢索對(duì)應(yīng)于“應(yīng)用程序服務(wù)代理”實(shí)例的 GUID。使用 GUID,它可以在服務(wù)代理注冊(cè)表中找到“應(yīng)用程序服務(wù)代理”。如果有對(duì)應(yīng)于 GUID 的“應(yīng)用程序服務(wù)代理”(原始“應(yīng)用程序服務(wù)代理”),ServiceAgentManager 會(huì)檢索原始的“應(yīng)用程序服務(wù)代理”以返回結(jié)果;否則,FailsafeServiceAgent 類將用作“聯(lián)機(jī)代理”執(zhí)行過(guò)程中處理錯(cuò)誤的最后手段。 |
? |
“服務(wù)代理管理器”將檢索“應(yīng)用程序服務(wù)代理”,然后使用 Payload 中的 ServiceAgentContext 信息來(lái)調(diào)用回調(diào)方法。該調(diào)用會(huì)在其他線程上進(jìn)行。“應(yīng)用程序服務(wù)代理”將適當(dāng)?shù)靥幚斫Y(jié)果。 |
圖 2.8.請(qǐng)求和響應(yīng)往返
應(yīng)用程序設(shè)計(jì)注意事項(xiàng)
到目前為止,本章已經(jīng)闡述了 Offline Application Block 的設(shè)計(jì)。本部分介紹有關(guān)智能客戶端應(yīng)用程序設(shè)計(jì)的注意事項(xiàng)。
服務(wù)代理的生命周期
“應(yīng)用程序服務(wù)代理”是生存期很長(zhǎng)的對(duì)象,這意味著它們至少可以在消息到其遠(yuǎn)程業(yè)務(wù)功能或服務(wù)的往返時(shí)間內(nèi)存在。(如果關(guān)閉應(yīng)用程序,則內(nèi)存中的“應(yīng)用程序服務(wù)代理”會(huì)被刷新。)每個(gè)“應(yīng)用程序服務(wù)代理”都會(huì)自動(dòng)向“服務(wù)代理注冊(cè)表”進(jìn)行注冊(cè),并由唯一的 GUID 標(biāo)識(shí)。這個(gè) GUID 用于將來(lái)自遠(yuǎn)程業(yè)務(wù)功能(服務(wù))的響應(yīng)返回到原始的“應(yīng)用程序服務(wù)代理”。如果原始的“應(yīng)用程序服務(wù)代理”(由其唯一的 GUID 標(biāo)識(shí))不再可用,則“服務(wù)代理管理器”將使用 FailsafeServiceAgent 來(lái)報(bào)告錯(cuò)誤。
在配置文件中定義多個(gè)提供程序
在配置文件中,您可以為單個(gè)配置區(qū)段定義多個(gè)提供程序。提供程序區(qū)段下面未啟用的提供程序或元素可以選擇性地在配置中使用 enabled="false",或者它們可以完全忽略已啟用的屬性。確保只啟用一個(gè)提供程序的算法封裝在 MultiProviderConfigHandler 類中。要在運(yùn)行時(shí)允許動(dòng)態(tài)更改配置文件,您可以使用 Configuration Management Application Block。
有關(guān)詳細(xì)信息,請(qǐng)參閱第 4 章中有關(guān)配置文件的部分。
線程
該塊可在其子系統(tǒng)中創(chuàng)建幾個(gè)內(nèi)部線程。它們包括:
? |
一個(gè)從應(yīng)用程序代碼中異步處理已排隊(duì)消息的線程。 |
? |
一個(gè)輪詢連接狀態(tài)更改并通知已注冊(cè)的組件狀態(tài)發(fā)生更改的線程。 |
重要的是,從這些線程的其中一個(gè)調(diào)用的應(yīng)用程序代碼不能在該調(diào)用中進(jìn)行長(zhǎng)時(shí)間處理,以避免延遲塊代碼。例如,如果應(yīng)用程序的連接狀態(tài)發(fā)生更改,“連接管理器”將調(diào)用已注冊(cè)對(duì)該類的 ConnectionStateChangedEvent 關(guān)注的任意類。該調(diào)用在“連接管理器”的連接檢測(cè)線程中進(jìn)行,因此由客戶端開(kāi)始的任何長(zhǎng)時(shí)間處理都會(huì)干擾“連接管理器”監(jiān)視是否存在后續(xù)的狀態(tài)更改。一般來(lái)說(shuō),事件處理代碼應(yīng)快速運(yùn)行,并且不應(yīng)回調(diào)到塊代碼中。
數(shù)據(jù)協(xié)調(diào)
該塊不處理數(shù)據(jù)協(xié)調(diào)。這是客戶端代碼或遠(yuǎn)程業(yè)務(wù)邏輯的責(zé)任。除了在“參考數(shù)據(jù)管理”部分中所述的“臟”或“過(guò)期”處理外,來(lái)自遠(yuǎn)程業(yè)務(wù)邏輯的結(jié)果將在本地覆寫所有可用的信息。例如,如果應(yīng)用程序更新了某個(gè)客戶的電話號(hào)碼,那么該更改會(huì)排入隊(duì)列,之后發(fā)出請(qǐng)求,然后收到包含操作成功通知的結(jié)果。但是,如果最終在服務(wù)器端更新該信息需要幾小時(shí)或幾天時(shí)間,那么就存在這樣的風(fēng)險(xiǎn):在此期間向服務(wù)器發(fā)出的獲取客戶電話號(hào)碼的請(qǐng)求可能會(huì)返回舊值。這已經(jīng)超出了該塊的范圍。開(kāi)發(fā)人員必須在應(yīng)用程序代碼或遠(yuǎn)程業(yè)務(wù)邏輯中提供解決方案。
在獨(dú)立的進(jìn)程中運(yùn)行組件
Offline Application Block 設(shè)計(jì)為完全在單個(gè)進(jìn)程中運(yùn)行。但是,塊中的某些組件可能會(huì)在多個(gè)進(jìn)程中運(yùn)行。
Executor 是最佳選擇。您可以將其作為一個(gè) Windows 服務(wù)運(yùn)行,當(dāng)應(yīng)用程序本身關(guān)閉時(shí)允許它為掛起的消息隊(duì)列提供服務(wù)。以下步驟介紹了實(shí)現(xiàn)方法:
? |
在生成器類中為 Executor 組件更新創(chuàng)建邏輯。同時(shí)還必須更新主生成器類。 |
? |
消息經(jīng)過(guò)處理后返回的結(jié)果必須在聯(lián)機(jī)和脫機(jī)方案中處理(將其返回到應(yīng)用程序)。實(shí)現(xiàn)這一點(diǎn)可以采取幾種不同的方法:您可以創(chuàng)建一個(gè)共享位置(例如緩存),將應(yīng)用程序的結(jié)果存儲(chǔ)在其中。您還可以獲取它們或使用某些內(nèi)部處理通信機(jī)制(例如遠(yuǎn)程處理),將結(jié)果返回應(yīng)用程序。 |
? |
“參考數(shù)據(jù)管理”和“消息數(shù)據(jù)管理”子系統(tǒng)必須能夠用于 Executor,以便能夠處理消息并更新緩存。這會(huì)影響到與應(yīng)用程序一起使用的隊(duì)列和緩存存儲(chǔ)提供程序,以及子系統(tǒng)本身的設(shè)計(jì)。 |
通過(guò)在獨(dú)立的進(jìn)程中運(yùn)行塊的一些組件,可以獲得較高的效率,包括為多個(gè)可能相關(guān)的應(yīng)用程序創(chuàng)建共享的緩存和隊(duì)列,以及創(chuàng)建同步消息數(shù)據(jù)和下載/刷新參考緩存數(shù)據(jù)的通用服務(wù)。但是,您還應(yīng)慎重考慮某些問(wèn)題,例如緩存架構(gòu)、組件之間的通信以及任何與爭(zhēng)用相關(guān)的問(wèn)題。
其他設(shè)計(jì)
Offline Application Block 的設(shè)計(jì)可使用異步行為來(lái)執(zhí)行消息。異步行為可防止在 UI 線程上執(zhí)行長(zhǎng)時(shí)間操作,這樣就提供了更好的用戶體驗(yàn)。
在某些情況下,如果網(wǎng)絡(luò)可靠并具有很高的帶寬,您可以考慮其他設(shè)計(jì),例如,僅當(dāng)應(yīng)用程序脫機(jī)時(shí),才會(huì)發(fā)生“應(yīng)用程序服務(wù)代理”將 Payload 排入隊(duì)列的情況。一旦應(yīng)用程序再次聯(lián)機(jī),它將繞過(guò) Offline Application Block 子系統(tǒng)而直接調(diào)用“聯(lián)機(jī)代理”。在處理請(qǐng)求后,“聯(lián)機(jī)代理”會(huì)將結(jié)果返回到“應(yīng)用程序服務(wù)代理”。這是 UI 線程上的同步調(diào)用,如果它是長(zhǎng)時(shí)間運(yùn)行的操作,則不建議使用,因?yàn)樗赡軙?huì)凍結(jié) UI。您可以通過(guò)調(diào)用其他線程(而不是 UI 線程)來(lái)進(jìn)行優(yōu)化,并使用 .NET 中提供的異步支持。
提示 要在“服務(wù)代理”中避免使用 if-else 語(yǔ)句,您可以使用狀態(tài)模式來(lái)根據(jù)狀態(tài)作出有關(guān)處理的決定。
小結(jié)
Offline Application Block 的設(shè)計(jì)為滿足應(yīng)用程序以脫機(jī)模式工作的需要提供了核心基礎(chǔ)結(jié)構(gòu)。它由下列子系統(tǒng)組成:
? |
連接狀態(tài)管理 |
? |
服務(wù)代理管理 |
? |
消息數(shù)據(jù)管理 |
? |
參考數(shù)據(jù)管理 |
? |
實(shí)用工具服務(wù) |
“連接狀態(tài)管理”子系統(tǒng)的主要角色是檢測(cè)連接狀態(tài),并通知偵聽(tīng)器有關(guān)任何狀態(tài)的變化。
“服務(wù)代理管理”子系統(tǒng)可實(shí)現(xiàn)下列功能
? |
維護(hù)“應(yīng)用程序服務(wù)代理”的注冊(cè)表 |
? |
包含負(fù)責(zé)在處理請(qǐng)求后將結(jié)果返回給“應(yīng)用程序服務(wù)代理”的組件 |
? |
提供應(yīng)用程序開(kāi)發(fā)人員用于實(shí)現(xiàn)應(yīng)用程序服務(wù)代理所必需的“服務(wù)代理”基類 |
“消息數(shù)據(jù)管理”子系統(tǒng)管理事務(wù)性數(shù)據(jù),并支持異步處理與應(yīng)用程序相關(guān)的消息。
“參考數(shù)據(jù)管理”子系統(tǒng)可為應(yīng)用程序提供基礎(chǔ)結(jié)構(gòu),用于在本地緩存數(shù)據(jù)并在數(shù)據(jù)變舊時(shí)刷新數(shù)據(jù)。通過(guò)允許加密和解密緩存的數(shù)據(jù),它還提供了安全存儲(chǔ)數(shù)據(jù)的能力。
“實(shí)用工具服務(wù)”子系統(tǒng)管理連接性和非池線程。
轉(zhuǎn)到原英文頁(yè)面