Offline Application Block 的設(shè)計

本頁內(nèi)容
Offline Application Block 是根據(jù) .NET 框架的功能并封裝智能客戶端應(yīng)用程序來構(gòu)建的,以幫助用戶在脫機時執(zhí)行任務(wù),就像用戶在聯(lián)機時執(zhí)行任務(wù)一樣簡單而有效。本章說明 Offline Application Block 的設(shè)計、功能以及融入其設(shè)計的決策。
脫機挑戰(zhàn)
智能客戶端應(yīng)用程序的開發(fā)人員在設(shè)計可以聯(lián)機和脫機運行的程序時,必須解決許多問題。通常發(fā)生的問題包括:
? |
應(yīng)用程序如何確定它處于聯(lián)機狀態(tài)還是脫機狀態(tài)? |
? |
如果連接能夠以不可預(yù)計的次數(shù)進行更改,那么應(yīng)該如何通知依賴于連接狀態(tài)的應(yīng)用程序組件呢? |
? |
應(yīng)用程序應(yīng)該如何存儲數(shù)據(jù)以及將數(shù)據(jù)存儲在本地的什么地方,才能在脫機狀態(tài)下對其進行訪問?數(shù)據(jù)會變陳舊嗎?應(yīng)該在何時刷新數(shù)據(jù)? |
? |
當(dāng)應(yīng)用程序無法訪問所有必需的數(shù)據(jù)或服務(wù)時,是否應(yīng)采用不同的運作方式? |
? |
當(dāng)應(yīng)用程序處于脫機狀態(tài)時,應(yīng)如何存儲事務(wù)性數(shù)據(jù)(消息數(shù)據(jù)),以及在何處存儲這些數(shù)據(jù)? |
? |
當(dāng)應(yīng)用程序從脫機變?yōu)槁?lián)機時,應(yīng)如何將事務(wù)性數(shù)據(jù)與服務(wù)器同步? |
解決方案說明
Offline Application Block 可以提供具有脫機功能的智能客戶端應(yīng)用程序所需的基本功能。其基本功能包括:
? |
檢測網(wǎng)絡(luò)連接是否存在。 |
? |
當(dāng)連接狀態(tài)變更時通知所有已注冊的組件。 |
? |
下載并緩存參考數(shù)據(jù),以便在網(wǎng)絡(luò)連接不可用時允許應(yīng)用程序正常工作。 |
? |
當(dāng)應(yīng)用程序脫機時,在本地存儲消息數(shù)據(jù)。 |
? |
當(dāng)網(wǎng)絡(luò)連接變?yōu)榭捎脮r,將消息數(shù)據(jù)與服務(wù)器進行同步。 |
設(shè)計目標(biāo)
Offline Application Block 旨在用作要將脫機功能包括在其應(yīng)用程序中的開發(fā)人員的體系結(jié)構(gòu)指南。該應(yīng)用程序塊的設(shè)計目標(biāo)為:
? |
在組件之間提供松耦合。 |
? |
抽象化應(yīng)用程序的連接狀態(tài)管理。 |
? |
為聯(lián)機和脫機模式下的應(yīng)用程序提供相同的編程模型,這樣應(yīng)用程序在這兩種模式之間的轉(zhuǎn)換不會影響用戶體驗。 |
? |
為諸如連接檢測和排隊這樣的功能提供可擴展的接口。 |
? |
合并設(shè)計模式。 |
設(shè)計注意事項
應(yīng)用程序塊體系結(jié)構(gòu)提倡使用可重復(fù)使用的封裝代碼組件。理想情況下,這些組件可設(shè)計為既可以互操作,又是模塊化的,以便代碼可以直接重復(fù)使用。在應(yīng)用程序中引用某個塊可以為應(yīng)用程序提供該塊的功能。
Offline Application Block 設(shè)計可提供邏輯和物理構(gòu)建塊,開發(fā)人員需要使用這些構(gòu)建塊將脫機功能合并到他們的應(yīng)用程序中。成功支持脫機操作的能力并不是通過簡單地添加構(gòu)建塊并調(diào)整現(xiàn)有的應(yīng)用程序就可以獲得。該構(gòu)建塊設(shè)計為推薦做法的一個示例 — 所提供的代碼僅闡述了可能的解決方案。在設(shè)計階段仔細(xì)計劃可以確保您的 Offline Application Block 應(yīng)用程序既可以重復(fù)使用又可以擴展。
模式
模式是可重復(fù)使用的解決方案,用于解決程序員可能在類似環(huán)境中遇到的重復(fù)出現(xiàn)的設(shè)計問題。在 Offline Application Block 的設(shè)計中使用了幾種模式,如表 2.1 中所述。
表 2.1:Offline Application Block 所使用的模式類型 | |
模式 | 說明 |
Builder |
從已創(chuàng)建組件的應(yīng)用程序邏輯中分離復(fù)雜的創(chuàng)建邏輯。允許應(yīng)用程序類的客戶端在創(chuàng)建塊組件的過程中保持獨立。 |
Factory |
構(gòu)建一個用于創(chuàng)建對象的接口,該接口應(yīng)在創(chuàng)建對象時允許子類選擇要實例化的類。 |
Observer |
在對象之間使用一對多的關(guān)系以獲得及時有效的通知。當(dāng)?shù)谝粋€對象更改時,所有相關(guān)的對象會立即獲得通知并自動進行更新。 |
Singleton |
提供對某個服務(wù)的單一、全局訪問點。Singleton 可用于只允許創(chuàng)建特定類的一個實例,并在需要該實例時提供對該單一實例的訪問。 |
Strategy |
提供定義一系列類似算法和接口(通過其訪問這些算法)的能力。所使用的特定算法的實現(xiàn)可以在不同時更改客戶端類的情況下進行更改。 |
Offline Application Block 設(shè)計
本部分說明了組成 Offline Application Block 的主要子系統(tǒng)的過程和體系結(jié)構(gòu)。有關(guān)主要子系統(tǒng)如何協(xié)同工作的詳細(xì)說明,請參閱本章的“請求和響應(yīng)往返”部分。
注 本部分只提供每個子系統(tǒng)類中最重要的方法和屬性的介紹。有關(guān)這些類及其成員的詳細(xì)信息,請參閱該應(yīng)用程序塊隨附的幫助文件。它位于 <安裝目錄>\Offline\Docs\ 文件夾中。
圖 2.1 展示了構(gòu)成脫機應(yīng)用程序的物理元素。

圖 2.1.Offline Application Block 的物理視圖
表 2.1 描述了圖 2.1 中的每個組件。這些組件將在本章中詳細(xì)討論。
表 2.2 智能客戶端應(yīng)用程序元素及其子系統(tǒng)和說明 | ||
元素 | 子系統(tǒng) | 說明 |
連接檢測策略 |
連接狀態(tài)管理 |
檢測物理連接的當(dāng)前狀態(tài) |
ConnectionManager |
連接狀態(tài)管理 |
管理與物理網(wǎng)絡(luò)訪問相關(guān)的連接狀態(tài)服務(wù)。使用可插入的連接檢測組件(通過實現(xiàn) IConnectionDetectionStrategy 接口)來確定連接狀態(tài)。當(dāng)“連接檢測策略”通知 ConnectionManager 連接狀態(tài)發(fā)生了變化,它就會觸發(fā)一個事件。ConnectionManager 還具有一些公共方法,應(yīng)用程序可以調(diào)用這些方法來手動更改應(yīng)用程序的聯(lián)機/脫機狀態(tài)。 |
Executor |
消息數(shù)據(jù)管理 |
在聯(lián)機時,從隊列中提取消息,并調(diào)用負(fù)責(zé)將消息發(fā)送到遠程服務(wù)的“聯(lián)機代理”。此外,它還負(fù)責(zé)將來自遠程服務(wù)的響應(yīng)發(fā)送回應(yīng)用程序。 |
隊列存儲 |
消息數(shù)據(jù)管理 |
提供用于保存消息數(shù)據(jù)的數(shù)據(jù)存儲區(qū),以及將在應(yīng)用程序再次聯(lián)機時發(fā)送給服務(wù)器的操作。 |
QueueManager |
消息數(shù)據(jù)管理 |
用作“隊列存儲提供程序”的一個接口。它提供消息入列和消息出列的方法。 |
DataLoaderManager |
參考數(shù)據(jù)管理 |
提供一種工具,以允許應(yīng)用程序在適當(dāng)?shù)臅r間請求要下載的參考數(shù)據(jù),以便在操作過程中使用。 |
ReferenceDataCache |
參考數(shù)據(jù)管理 |
用作“參考數(shù)據(jù)管理”子系統(tǒng)的一個接口。它負(fù)責(zé)確保應(yīng)用程序所需的數(shù)據(jù)已存儲,并可以在應(yīng)用程序處于脫機狀態(tài)時進行本地訪問(緩存)。 |
緩存塊 |
參考數(shù)據(jù)管理 |
提供一個物理緩存操作的實現(xiàn)。 |
應(yīng)用程序服務(wù)代理 |
服務(wù)代理管理 |
提供隊列消息的能力。它還提供了一個將結(jié)果返回應(yīng)用程序的通道。 |
Online Proxy |
服務(wù)代理管理 |
由應(yīng)用程序開發(fā)人員創(chuàng)建的類,它負(fù)責(zé)與提供業(yè)務(wù)功能的遠程服務(wù)進行通信。如果需要,“聯(lián)機代理”還可以負(fù)責(zé)在緩存中存儲參考數(shù)據(jù)。 |
ServiceAgent |
服務(wù)代理管理 |
提供由應(yīng)用程序提供的所有服務(wù)代理所實現(xiàn)的基類。“服務(wù)代理”基類負(fù)責(zé)在服務(wù)代理注冊表中注冊服務(wù)代理。 |
ServiceAgentManager |
服務(wù)代理管理 |
處理后,“服務(wù)代理管理器”會將結(jié)果返回到相應(yīng)的“服務(wù)代理”。 |
說明性方案
以下方案顯示了用戶所采取的操作如何轉(zhuǎn)換為在智能客戶端應(yīng)用程序內(nèi)部發(fā)生的操作。有關(guān)構(gòu)成 Offline Application Block 的元素是如何協(xié)同工作的整體概述,請參閱前面的圖 2.1。
準(zhǔn)備脫機工作
David 已連接到網(wǎng)絡(luò),并且正在運行用于填寫其責(zé)任區(qū)域的保險理賠的應(yīng)用程序。他按計劃到現(xiàn)場處理這個理賠。David 單擊“Download Work Items”按鈕以下載他需要完成的所有理賠。
應(yīng)用程序操作
在運行時,應(yīng)用程序?qū)m當(dāng)?shù)摹皯?yīng)用程序服務(wù)代理”進行方法調(diào)用以下載數(shù)據(jù)。然后,“應(yīng)用程序服務(wù)代理”再調(diào)用 DataLoaderManager 以初始化下載。DataLoaderManager 調(diào)用 QueueManager,并將數(shù)據(jù)下載請求置于隊列中。如果系統(tǒng)處于聯(lián)機狀態(tài),則 Executor 將提取該請求,然后通過反射創(chuàng)建 OnlineProxy 的實例并調(diào)用指定的方法來處理該請求。然后,“聯(lián)機代理”與遠程服務(wù)器進行通信并獲得所需的數(shù)據(jù)。它通過使用 ReferenceDataCache 將數(shù)據(jù)存儲在本地計算機的緩存中。然后,Executor 調(diào)用“服務(wù)代理管理器”以返回結(jié)果。接下來,“服務(wù)代理管理器”對特定“應(yīng)用程序服務(wù)代理”進行回調(diào)。最后,“應(yīng)用程序服務(wù)代理”引發(fā)一個事件來通知應(yīng)用程序有關(guān)已下載數(shù)據(jù)的信息。
圖 2.2 闡釋了應(yīng)用程序用于下載參考數(shù)據(jù)的過程。
注 Offline Application Block 會保留部分緩存,并將其命名為“參考數(shù)據(jù)緩存”。該緩存只管理參考數(shù)據(jù)。您可以使用為您的組織而設(shè)計的數(shù)據(jù)存儲區(qū)來創(chuàng)建新緩存。

圖 2.2.下載參考數(shù)據(jù)時涉及的塊的各個部分
脫機工作
David 隨身攜帶了計算機。當(dāng)他再次訪問該應(yīng)用程序時,計算機沒有連接到網(wǎng)絡(luò),應(yīng)用程序是在脫機模式下啟動的。David 在與他的客戶協(xié)商后完成了理賠。
應(yīng)用程序操作
應(yīng)用程序向 ConnectionManager 注冊以接收連接狀態(tài)更改事件。ConnectionManager 將使用 ConnectionDetectionStrategy 來確定計算機處于脫機狀態(tài),并觸發(fā)一個事件以通知所有注冊的組件。
注 組件必須向“連接管理器”注冊,才能收到狀態(tài)更改事件的通知。
圖 2.3 闡釋了應(yīng)用程序用于檢測與網(wǎng)絡(luò)的連接性的過程。

圖 2.3.脫機過程中涉及的塊的各個組件
完成理賠
David 在應(yīng)用程序中打開一個理賠,完成該理賠,然后單擊“Submit”按鈕。
應(yīng)用程序操作
應(yīng)用程序會在內(nèi)部調(diào)用“應(yīng)用程序服務(wù)代理”來處理工作項目。“服務(wù)代理”將創(chuàng)建一個包含該工作項目的 Payload。在創(chuàng)建 Payload 之后,“服務(wù)代理”會調(diào)用“隊列管理器”將消息數(shù)據(jù)存儲在隊列中。QueueManager 將 Payload 封裝在一個 QueueMessage 中,并將其保留在隊列中。
圖 2.4 闡釋了應(yīng)用程序用于在脫機狀態(tài)下完成理賠的過程。

圖 2.4.在脫機狀態(tài)下完成理賠所涉及的塊的各個部分
同步脫機數(shù)據(jù)
David 返回辦公室,將計算機連接到網(wǎng)絡(luò),然后啟動應(yīng)用程序。
應(yīng)用程序操作
一旦連接狀態(tài)變?yōu)槁?lián)機,就會在單獨的線程上激活 Executor。然后,Executor 開始檢索隊列中的隊列消息。對于每個 QueueMessage,Executor 會調(diào)用 OnlineProxy(這是一個使用反射創(chuàng)建的對象,它使用 Payload 中包含的 onlineProxyContext 信息)的指定方法,將工作項目信息提交到遠程服務(wù)以便進行處理。處理工作項目后,遠程服務(wù)會將結(jié)果返回到 Executor。
然后,Executor 將包含結(jié)果的 Payload 返回到“服務(wù)代理管理器”,隨后該管理器會在 ServiceAgentRegistry 中查找“應(yīng)用程序服務(wù)代理”。它將響應(yīng)發(fā)送到該“應(yīng)用程序服務(wù)代理”。“應(yīng)用程序服務(wù)代理”會在更新數(shù)據(jù)時通知用戶界面。所有理賠都以透明的方式進行同步。
如果消息執(zhí)行失敗,并且原來的“應(yīng)用程序服務(wù)代理”不再可用,則“服務(wù)代理管理器”會將響應(yīng)發(fā)送到 FailsafeServiceAgent。
圖 2.5 闡釋了“服務(wù)代理管理”子系統(tǒng)執(zhí)行的步驟。

圖 2.5.添加脫機數(shù)據(jù)時所涉及的塊的各個部分
Offline Application Block 子系統(tǒng)
子系統(tǒng)的標(biāo)準(zhǔn)定義是:一起工作以完成指定目標(biāo)的一組獨立的類。通過將 Offline Application Block 劃分為下列邏輯子系統(tǒng),可以充分地理解它:
? |
連接狀態(tài)管理 |
? |
服務(wù)代理管理 |
? |
消息數(shù)據(jù)管理 |
? |
參考數(shù)據(jù)管理 |
? |
實用工具服務(wù) |
“連接狀態(tài)管理”子系統(tǒng)監(jiān)視應(yīng)用程序的聯(lián)機/脫機狀態(tài),并通知已注冊的偵聽器。“連接狀態(tài)管理”可處理所有連接狀態(tài)任務(wù)(那些與檢測物理連接相關(guān)的任務(wù)),并且可以進行擴展,以檢測并連接到某個服務(wù),并可以檢測服務(wù)在何時不可用。
“服務(wù)代理管理”子系統(tǒng)控制“應(yīng)用程序服務(wù)代理”以及與 Executor 類的接口。
“消息數(shù)據(jù)管理”和“參考數(shù)據(jù)管理”子系統(tǒng)協(xié)同工作,以確保首次嘗試訪問數(shù)據(jù)項目時數(shù)據(jù)的可用性。
“實用工具服務(wù)”管理連接性和非池線程 — 這意味著,線程管理對開發(fā)人員是透明的。
下列各部分給出了有關(guān)每個子系統(tǒng)的詳細(xì)信息。
連接狀態(tài)管理
“連接狀態(tài)管理”子系統(tǒng)的主要角色是:檢測連接狀態(tài)并通知偵聽器任何狀態(tài)變化。要擴展其智能客戶端應(yīng)用程序以包含脫機功能的開發(fā)人員,可能希望將應(yīng)用程序設(shè)計為在聯(lián)機工作和脫機工作時具有不同的行為。應(yīng)用程序是處于聯(lián)機狀態(tài)還是脫機狀態(tài),由下列兩個因素的其中一個決定:
? |
常規(guī)網(wǎng)絡(luò)連接是否存在 — 應(yīng)用程序是否能夠訪問遠程資源和服務(wù)? |
? |
來自應(yīng)用程序用戶的明確指令。應(yīng)用程序可能允許用戶將連接狀態(tài)設(shè)置為脫機,即使第一個因素指示應(yīng)用程序處于聯(lián)機狀態(tài)。 |
類設(shè)計
“連接狀態(tài)管理”子系統(tǒng)包含的類可管理連接檢測和通知服務(wù)以及線程管理組件。這些類包括 ConnectionManager 類和 ConnectionDetector 類。
ConnectionManager 類
ConnectionManager 類是“連接狀態(tài)管理”子系統(tǒng)的一個接口,并且是 Observer 模式的一個示例。它負(fù)責(zé)管理連接狀態(tài)變化的檢測,以及在發(fā)生變化時通知相應(yīng)的對象。它還提供了用于強制應(yīng)用程序脫機或聯(lián)機的方法。
類成員
以下部分(“方法”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請參閱該應(yīng)用程序塊中隨附的幫助文件。
方法
? |
GoOffline – 強制系統(tǒng)脫機。 |
? |
GoOnline – 強制系統(tǒng)聯(lián)機。 |
ConnectionDetector 類
ConnectionDetector 類管理發(fā)生的狀態(tài)轉(zhuǎn)換,這些轉(zhuǎn)換是由派生的 IConnectionDetectionStrategy 接口實現(xiàn)檢測到的。IConnectionDetectionStrategy 接口提供了檢測物理連接當(dāng)前狀態(tài)的功能,而 ConnectionDetector 類提供了檢測狀態(tài)變化的功能。
IConnectionDetectionStrategy 接口
“連接狀態(tài)管理”子系統(tǒng)支持不同的連接檢測實現(xiàn)(也稱為提供程序),以檢測連接是否存在。該子系統(tǒng)使用 Strategy 模式,可允許在不更改應(yīng)用程序代碼的情況下更改連接檢測算法。每個連接檢測提供程序都必須實現(xiàn) IConnectionDetectionStrategy 接口,以便該提供程序可以與應(yīng)用程序塊一起使用。
通過實現(xiàn)該接口并在應(yīng)用程序的配置文件中指定必要的配置信息,應(yīng)用程序開發(fā)人員可以創(chuàng)建他們自己的連接檢測策略。
盡管可以在配置文件中定義多個策略,但只應(yīng)該在配置文件中啟用其中一個策略。
該應(yīng)用程序塊附帶一個名為 WinInetDetectionStrategy 的連接檢測提供程序,它使用 Windows 網(wǎng)絡(luò) API (WinInet) 來檢測網(wǎng)絡(luò)連接是否存在。有關(guān)詳細(xì)信息,請參閱本指南隨附的幫助文件。
服務(wù)代理管理
“服務(wù)代理管理”子系統(tǒng)執(zhí)行下列操作:
? |
維護“應(yīng)用程序服務(wù)代理”的注冊表 |
? |
包含負(fù)責(zé)在處理請求后將結(jié)果返回給“應(yīng)用程序服務(wù)代理”的組件 |
? |
提供應(yīng)用程序開發(fā)人員用于實現(xiàn)應(yīng)用程序服務(wù)代理所必需的“服務(wù)代理”基類 |
設(shè)計用于 Offline Application Block 的“服務(wù)代理”
正如第 1 章中討論的那樣,Offline Application Block 使用面向服務(wù)的方法為智能客戶端應(yīng)用程序提供脫機功能。使用該方法,“服務(wù)代理”可以與提供各種業(yè)務(wù)功能的不同類型的遠程服務(wù)一起工作。這些業(yè)務(wù)功能可作為 Web 服務(wù)在服務(wù)器端公開。“服務(wù)代理”也需要與“緩存管理”、“隊列管理”和“消息數(shù)據(jù)管理”子系統(tǒng)進行交互。
由于這些交互,“服務(wù)代理”可能要在這些子系統(tǒng)之間進行多次往返。您可以設(shè)計一個具有不同任務(wù)粒度級別的“服務(wù)代理”。您還可以在“服務(wù)代理”與遠程服務(wù)進行通信時添加粒度。這些方法可以包含:
? |
與單個任務(wù)進行交互的“服務(wù)代理”。例如,它可以創(chuàng)建一個客戶。 |
? |
與和某個實體相關(guān)的所有任務(wù)進行交互的“服務(wù)代理”。例如,它可以在客戶實體上執(zhí)行創(chuàng)建、讀取、更新和刪除操作。 |
? |
只處理一個特定服務(wù)的“服務(wù)代理” |
? |
處理多個服務(wù)的“服務(wù)代理” |
在 Offline Application Block 的設(shè)計中,“服務(wù)代理”的責(zé)任劃分為兩個類:它們是:
? |
ServiceAgent – 該類在塊中本地執(zhí)行所有任務(wù)。這些任務(wù)可以包括創(chuàng)建和排列 Payload、更新本地緩存或從本地緩存中檢索滿足該請求所需的所有數(shù)據(jù)。在設(shè)計新的脫機塊時,開發(fā)人員應(yīng)該從 Offline Application Block 提供的 ServiceAgent 類中派生一個新的“應(yīng)用程序服務(wù)代理”類。 |
? |
OnlineProxy – 該類抽象了與提供業(yè)務(wù)功能的服務(wù)進行交互的功能。應(yīng)用程序開發(fā)人員必須創(chuàng)建他們自己的“聯(lián)機代理”。 |
使用兩個類(而不是單個類)的原因是:當(dāng) Offline Application Block 需要與 Web 服務(wù)進行通信時,需要創(chuàng)建并使用多個代理。為此,這些代理應(yīng)是無狀態(tài)的。
類設(shè)計
“服務(wù)代理管理”子系統(tǒng)包括要從 Executor 中獲取響應(yīng)、然后將結(jié)果傳回“應(yīng)用程序服務(wù)代理”的類。如果出現(xiàn)錯誤并且原來的“應(yīng)用程序服務(wù)代理”不可用,則錯誤被傳遞到“Failsafe 服務(wù)代理”。
ServiceAgent 類
Offline Application Block 提供了一個 ServiceAgent 類。這個基類抽象了所有“應(yīng)用程序服務(wù)代理”的常見行為和數(shù)據(jù)。
ServiceAgent 基類最重要的責(zé)任是向 ServiceAgentRegistry 注冊“應(yīng)用程序服務(wù)代理”的所有實例。(該過程在抽象后置于 Service Agent 基類中,以增加代碼的可重復(fù)使用性。)“服務(wù)代理注冊表”用于在消息處理過程中,將事務(wù)的成功或失敗消息返回到原始的“應(yīng)用程序服務(wù)代理”。對基類的構(gòu)造函數(shù)中的所有派生類透明地完成該注冊。
類成員
以下部分(“屬性”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請參閱該應(yīng)用程序塊隨附的幫助文件。
屬性
GUID – ServiceAgent 類的每個實例的全局唯一標(biāo)識符 (GUID)。GUID 可唯一標(biāo)識 ServiceAgentRegistry 中的特定“應(yīng)用程序服務(wù)代理”。
FailsafeServiceAgent 類
Offline Application Block 的設(shè)計目標(biāo)是將“聯(lián)機代理”執(zhí)行的結(jié)果返回到原始的“應(yīng)用程序服務(wù)代理”(如果該原始“應(yīng)用程序服務(wù)代理”仍然存在)。原始代理可能不存在的原因有以下幾個:
? |
應(yīng)用程序可能顯式地將其從系統(tǒng)中刪除。 |
? |
應(yīng)用程序可能被關(guān)閉然后重新開啟。 |
一旦“應(yīng)用程序服務(wù)代理”被損壞,則來自“聯(lián)機代理”的所有錯誤都會丟失,這是因為原始服務(wù)代理已不再接收它們。在某些情況下,這還會導(dǎo)致數(shù)據(jù)丟失。為防止出現(xiàn)這種情況,該應(yīng)用程序塊提供了 FailsafeServiceAgent。
FailsafeServiceAgent 類很常用,它是“聯(lián)機代理”執(zhí)行過程中處理錯誤的最后手段。它并不是通過其正常返回錯誤的默認(rèn)“服務(wù)代理”。如果發(fā)生了以下所有事件,則結(jié)果將被返回到 FailsafeServiceAgent:
? |
該應(yīng)用程序塊在 Executor 中執(zhí)行“聯(lián)機代理”。 |
? |
該“聯(lián)機代理”失敗。 |
? |
找不到原始的“應(yīng)用程序服務(wù)代理”。 |
為了使該返回機制正常工作,應(yīng)用程序必須滿足以下要求:
? |
只使用從 OfflineBlockBuilder 檢索的 FailsafeServiceAgent 的實例。 |
? |
始終維護在 FailsafeServiceAgent 類的 ErrorEvent 中注冊的回調(diào)方法。 |
ServiceAgentContext 類
當(dāng)“服務(wù)代理管理器”調(diào)用“應(yīng)用程序服務(wù)代理”的一個方法時,會從 ServiceAgentContext 類中檢索要調(diào)用的相應(yīng)方法。Payload(在本章的“消息數(shù)據(jù)管理”部分中定義)可為每個請求提供“服務(wù)代理”上下文。
類成員
以下部分(“屬性”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請參閱該應(yīng)用程序塊隨附的幫助文件。
屬性
MethodToInvoke – 返回要調(diào)用的方法名稱。“服務(wù)代理管理器”調(diào)用“應(yīng)用程序服務(wù)代理”的這個方法,以傳回請求的結(jié)果。
OnlineProxyContext 類
OnlineProxyContext 類可封裝調(diào)用“聯(lián)機代理”的遠程服務(wù)請求行為所必需的信息。Payload(在后面的“消息數(shù)據(jù)管理”部分中定義)可為每個請求提供“聯(lián)機代理”上下文。
ServiceAgentManager類
ServiceAgentManager 可將服務(wù)請求的結(jié)果返回到適當(dāng)?shù)摹皯?yīng)用程序服務(wù)代理”。代理是由其 GUID 識別的。ServiceAgentManager 使用 GUID 從“服務(wù)代理注冊表”中獲得特定“應(yīng)用程序服務(wù)代理”的實例 — 它會調(diào)用指定的“應(yīng)用程序服務(wù)代理”方法。每次實例化一個“應(yīng)用程序服務(wù)代理”,它就會得到一個新的 GUID。
ServiceAgentRegistry 類
ServiceAgentRegistry 類可作為當(dāng)前活動的“應(yīng)用程序服務(wù)代理”的儲備庫。在創(chuàng)建“應(yīng)用程序服務(wù)代理”時,會將它們添加到注冊表中。“服務(wù)代理管理器”根據(jù) GUID 來查找“應(yīng)用程序服務(wù)代理”。每個 GUID 都表示一個實例化的“應(yīng)用程序服務(wù)代理”。
ThreadPoolInvoker 類
在處理請求后,“服務(wù)代理管理器”使用 ThreadPoolInvoker 類將結(jié)果傳回位于線程池線程上的“應(yīng)用程序服務(wù)代理”回調(diào)方法。
消息數(shù)據(jù)管理
“消息數(shù)據(jù)管理”子系統(tǒng)管理存儲在隊列中的事務(wù)性數(shù)據(jù),并提供將同步數(shù)據(jù)的功能添加到服務(wù)器的基礎(chǔ)結(jié)構(gòu)。該子系統(tǒng)由下列組件構(gòu)成:
? |
隊列消息 – QueueMessage 類是存儲在隊列中的消息的容器。 |
? |
隊列管理器 – QueueManager 是“消息數(shù)據(jù)管理”子系統(tǒng)的一個接口,它公開了將消息添加到隊列以及從隊列中刪除消息的方法。 |
? |
Executor – Executor 類從隊列中檢索消息,然后將它們發(fā)送到處理該請求的適當(dāng)“聯(lián)機代理”。Executor 根據(jù) QueueMessage 中的可用信息使用反射來實例化“聯(lián)機代理”。 |
? |
隊列存儲提供程序 – 這些類抽象了與物理隊列存儲區(qū)的交互。該應(yīng)用程序塊附帶了用于 Microsoft 消息隊列 (MSMQ)、Microsoft SQL Server? 桌面引擎 (MSDE)、獨立的存儲區(qū)以及內(nèi)存的提供程序。 |
類設(shè)計
“消息數(shù)據(jù)管理”子系統(tǒng)支持異步處理與應(yīng)用程序相關(guān)的消息:
? |
提供一致的用戶體驗,無論是聯(lián)機狀態(tài)還是脫機狀態(tài)。無論連接狀態(tài)如何,“消息數(shù)據(jù)管理”都能夠排列要異步執(zhí)行的所有消息。當(dāng)應(yīng)用程序處于聯(lián)機狀態(tài)時,就會執(zhí)行消息。 |
? |
避免阻塞運行過程較長的 UI 線程。 |
QueueMessage 類
QueueMessage 類是存儲在隊列中的數(shù)據(jù)的容器。Payload 是“隊列消息”攜帶的關(guān)鍵元素。開發(fā)人員可以將 QueueMessage 類視作基類,并對其進行擴展以添加他們的應(yīng)用程序所需的任何附加功能。
類成員
以下部分(“屬性”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請參閱該應(yīng)用程序塊中隨附的幫助文件。
屬性
MessagePayload – 返回一個類型為 Payload 的對象。Payload 包含用于處理請求的數(shù)據(jù)。它還包括有關(guān)處理請求以及返回結(jié)果的組件的元數(shù)據(jù)。
QueueManager 類
QueueManager 類是“消息數(shù)據(jù)管理”子系統(tǒng)的一個接口,它具有以下功能:
? |
它是一個線程安全的組件,可以在多個線程上同時被訪問。 |
? |
根據(jù)應(yīng)用程序的配置設(shè)置,它可以實例化適當(dāng)?shù)年犃写鎯μ峁┏绦颍ㄍㄟ^實現(xiàn) IQueueStorageProvider 接口)。 |
? |
它可以公開在隊列中添加和刪除消息的方法。 |
為了保持消息的順序,Offline Application Block 可在“隊列管理器”中強制使用“先進先出”(FIFO) 語義。
類成員
以下部分(“方法”和“屬性”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請參閱該應(yīng)用程序塊中隨附的幫助文件。
方法
? |
Enqueue – 將消息添加到隊列中。它可以接受類型為 Payload 的參數(shù)作為輸入。該方法將 Payload 輸入封裝在 QueueMessage 中,然后使用指定的隊列存儲提供程序?qū)⑵浯鎯υ陉犃兄小? |
? |
Dequeue – 使用指定的隊列存儲提供程序從隊列中刪除和返回消息。 |
屬性
Size – 返回與隊列大小相對應(yīng)的 System.Int32 值。
Payload 類
Payload 類是處理一個消息所需的所有信息的數(shù)據(jù)容器。它包含:
? |
要調(diào)用的“聯(lián)機代理”方法的名稱。 |
? |
要發(fā)送到服務(wù)器的數(shù)據(jù)。 |
? |
從服務(wù)器接收的數(shù)據(jù)。 |
? |
應(yīng)接收返回數(shù)據(jù)的“應(yīng)用程序服務(wù)代理”的標(biāo)識。 |
在大多數(shù)情況下,該類應(yīng)可以滿足任何開發(fā)人員的要求,但是如有必要,可以擴展它以包含其他消息數(shù)據(jù)。
類成員
以下部分(“方法”和“屬性”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請參閱該應(yīng)用程序塊中隨附的幫助文件。
方法
RecordFailure – Payload 類上公開的方法,它可記錄在處理請求的過程中所發(fā)生的任何故障。該方法可接受 Exception 作為參數(shù),并為 Payload 類的這個實例設(shè)置 FailureReason 值。
屬性
? |
PayloadGuid – 為 Payload 類的每個實例生成的全局唯一標(biāo)識符 (GUID)。應(yīng)用程序可以使用此信息來關(guān)聯(lián)數(shù)據(jù);但應(yīng)用程序塊并沒有提供支持它的任何基礎(chǔ)結(jié)構(gòu)。 |
? |
ServiceAgentGuid – 為“應(yīng)用程序服務(wù)代理”的每個對象所生成的全局唯一標(biāo)識符 (GUID)。當(dāng)結(jié)果在處理后被傳回正確的“應(yīng)用程序服務(wù)代理”時,在“服務(wù)代理管理器”中使用 GUID 從注冊表中檢索“應(yīng)用程序服務(wù)代理”。 |
? |
MethodToExecute – 包含調(diào)用特定聯(lián)機代理方法的 OnlineProxyContext 的實例。 |
? |
ResultCallbackTarget – 包含將結(jié)果返回到“應(yīng)用程序服務(wù)代理”的 ServiceAgentContext 的實例。 |
? |
RequestData – 包含處理創(chuàng)建 Payload 的請求所必需的數(shù)據(jù)。它由創(chuàng)建 Payload 的“服務(wù)代理”填充。 |
? |
Results – 包含處理請求的結(jié)果。它由與服務(wù)進行通信的“聯(lián)機代理”填充。 |
? |
FailureReason – 返回一個類型為 System.Exception 的對象,該對象包含由于處理請求中的故障而產(chǎn)生的異常。 |
? |
Success – 返回一個布爾值,表示請求處理是否成功。 |
Executor 類
Executor 類從隊列中檢索消息。它運行在自己的線程上,每秒輪詢一次隊列以檢查是否有新消息,并持續(xù)處理消息直到隊列為空。然后,它在再次檢查是否存在可用消息前停止 1 秒鐘。從隊列中檢索一個消息后,Executor 會調(diào)用實現(xiàn) ICommandProcessor 接口的類的實例上的方法,來執(zhí)行該消息。
SimpleCommandProcessor 類
SimpleCommandProcessor 類實現(xiàn) ICommandProcessor 接口,并通過實例化適當(dāng)?shù)摹奥?lián)機代理”并將結(jié)果返回到指定的結(jié)果回調(diào)目標(biāo),來使用反射執(zhí)行消息。該應(yīng)用程序塊將 ServiceAgentManager 用作返回結(jié)果的默認(rèn)目標(biāo)。
IQueueStorageProvider 接口
使用隊列存儲提供程序,可以將消息數(shù)據(jù)存儲在幾種不同類型的物理存儲區(qū)中。每個隊列存儲提供程序都必須實現(xiàn) IQueueStorageProvider 接口,才能用于應(yīng)用程序塊。QueueManagerBuilder 類可實例化隊列存儲提供程序,并將其傳遞到 QueueManager。
通過實現(xiàn)這個接口并在應(yīng)用程序配置文件中指定必要的配置信息,應(yīng)用程序開發(fā)人員可以創(chuàng)建他們自己的隊列存儲提供程序。
盡管在配置文件中可以定義多個提供程序,但是在配置文件中只應(yīng)該啟用其中一個提供程序。如果配置文件中的提供程序發(fā)生更改,則該應(yīng)用程序塊將其視為用于存儲消息數(shù)據(jù)的新提供程序。該應(yīng)用程序塊沒有將數(shù)據(jù)從以前的存儲區(qū)移到新存儲區(qū)的內(nèi)置功能。
該應(yīng)用程序塊附帶四個隊列存儲提供程序:
? |
In Memory – 該提供程序在 InMemoryQueueStorageProvider 類中實現(xiàn)。它將隊列數(shù)據(jù)存儲在一個內(nèi)存數(shù)據(jù)結(jié)構(gòu) (System.Collection.Queue) 中。當(dāng)應(yīng)用程序重新啟動時,所存儲的數(shù)據(jù)將會丟失。不建議使用該提供程序存儲持久性數(shù)據(jù)。 |
? |
Isolated Storage – 該提供程序在 IsolatedStorageQueueStorageProvider 類中實現(xiàn)。它將隊列數(shù)據(jù)存儲到獨立存儲區(qū)中。建議使用該提供程序存儲持久性數(shù)據(jù)。 |
? |
MSDE – 該提供程序在 msdeQueueStorageProvider 類中實現(xiàn)。它將隊列數(shù)據(jù)存儲在 MSDE 中。建議使用該提供程序存儲持久性數(shù)據(jù)。 |
? |
MSMQ – 該提供程序在 msmqQueueStorageProvider 類中實現(xiàn)。它將隊列數(shù)據(jù)存儲在“消息隊列”中。該提供程序的自定義屬性位于配置文件中,并且可以定義隊列的名稱。建議使用該提供程序存儲持久性數(shù)據(jù)。 |
參考數(shù)據(jù)管理
即使處于脫機狀態(tài),智能客戶端應(yīng)用程序也必須為用戶提供他們繼續(xù)工作所需的數(shù)據(jù)。此數(shù)據(jù)通常稱為參考數(shù)據(jù),它在本地進行緩存,并且在數(shù)據(jù)過期變舊時會進行周期刷新。
參考數(shù)據(jù)通常是靜態(tài)的,但有時也可能被應(yīng)用程序更改。當(dāng)出現(xiàn)這種情況時,Offline Application Block 會將數(shù)據(jù)標(biāo)記為 dirty。這樣會防止應(yīng)用程序塊在數(shù)據(jù)過期時刷新數(shù)據(jù),并且可以避免來自其他源的舊值覆寫已更新的數(shù)據(jù)。在更新與遠程服務(wù)進行同步后,數(shù)據(jù)被標(biāo)記為 clean,并且可以進行刷新。
“參考數(shù)據(jù)管理”子系統(tǒng)可為應(yīng)用程序提供基礎(chǔ)結(jié)構(gòu),用于在本地緩存數(shù)據(jù)并在數(shù)據(jù)變舊時刷新數(shù)據(jù)。通過允許加密和解密緩存的數(shù)據(jù),它還提供了安全存儲數(shù)據(jù)的能力。
該子系統(tǒng)使用 Caching Application Block,它由下列組件構(gòu)成:
? |
ReferenceDataCache – Offline Application Block 通過該封裝程序公開帶有支持聯(lián)機/脫機方案附加功能的緩存行為。 |
? |
ReferenceDataDefinition – 與參考緩存中的項目相關(guān)聯(lián)的元數(shù)據(jù)。它控制信息的刷新方式、信息何時過期以及維護數(shù)據(jù)的 dirty 和 clean 狀態(tài)標(biāo)記。 |
? |
ReferenceDataRefreshController – 當(dāng)某個項目過期時,該類負(fù)責(zé)將該項目添加回緩存。它與 DataLoaderManager 協(xié)作來刷新緩存項目。 |
? |
DataLoaderManager – 該類可創(chuàng)建 ReferenceCacheDataPayload 并將消息添加到隊列中,以便下載參考數(shù)據(jù)并將其存儲到緩存中。 |
? |
ReferenceCacheDataPayload – 該類可利用對 ReferenceDataDefinition(包含更新參考緩存數(shù)據(jù)所必需的元數(shù)據(jù))的參考,來擴展 Payload 類。 |
有關(guān)“參考數(shù)據(jù)管理”子系統(tǒng)如何工作的進一步說明,請參閱本章的“參考數(shù)據(jù)緩存工作流”部分。
類設(shè)計
“參考數(shù)據(jù)管理”子系統(tǒng)提供了用于管理處理緩存、存儲和刷新數(shù)據(jù)的組件的類。
ReferenceDataCache 類
該應(yīng)用程序塊通過該封裝程序公開帶有支持脫機和聯(lián)機方案附加功能的緩存行為。該類實現(xiàn) IReferenceDataCache,并且該類的客戶端應(yīng)訪問這種類型的對象。
類成員
以下部分(“方法”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請參閱該應(yīng)用程序塊中隨附的幫助文件。
方法
? |
Store – 使用指定的緩存項來存儲參考緩存數(shù)據(jù)項目。Store 不要求緩存中存在項目。 |
? |
Update – 在緩存項指定的位置更新參考緩存數(shù)據(jù)項目。Update 要求緩存中存在項目。 |
? |
Retrieve – 對于給定的緩存項,檢索參考緩存數(shù)據(jù)項目。 |
? |
Remove – 對于給定的緩存項,刪除參考緩存數(shù)據(jù)項目。 |
? |
IsDirty – 返回一個布爾值,表示位于指定緩存項位置的項目是否已由應(yīng)用程序修改。 |
? |
MarkAsClean – 如果參考數(shù)據(jù)緩存項目存在于緩存中,它會將該項目標(biāo)記為 clean。這表示作為工作流(在指定的緩存項位置修改參考數(shù)據(jù)項目)一部分而生成的消息已經(jīng)進行了處理。 |
? |
ItemHasBeenExpired – 用于將項目標(biāo)記為“已過期”的方法。 |
ReferenceDataDefinition 類
該類包含與參考緩存中的項目相關(guān)聯(lián)的元數(shù)據(jù)。它控制信息的刷新方式、信息何時過期以及維護數(shù)據(jù)的 dirty 和 clean 狀態(tài)標(biāo)記。
ReferenceDataRefreshController 類
當(dāng)某個項目過期時,該類負(fù)責(zé)將該項目添加回緩存。它與 DataLoaderManager 協(xié)作來刷新隊列。
該功能必須作為獨立的類存在,而不是嵌入到 ReferenceDataCache 本身中,它促進了應(yīng)用程序塊中各個元素之間的松散耦合。使 ReferenceDataCache 依賴于 DataLoaderManager 會不必要地耦合這兩個子系統(tǒng)。通過將該責(zé)任轉(zhuǎn)移給第三類,可以消除這種依存關(guān)系,并可以使整個應(yīng)用程序塊保持松散耦合。為了正常工作,該類需要訪問 ReferenceDataCache 和 DataLoaderManager。
DataLoaderManager 類
該類負(fù)責(zé)下載參考數(shù)據(jù)。為此,它將創(chuàng)建 ReferenceCacheDataPayload 并將其添加到隊列中,以便可以處理消息和下載參考數(shù)據(jù)。下載的參考數(shù)據(jù)存儲在緩存中。
類成員
以下部分(“方法”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請參閱該應(yīng)用程序塊中隨附的幫助文件。
方法
? |
LoadData – 創(chuàng)建 ReferenceCacheDataPayload 并將其排入隊列以便異步處理,來開始下載參考數(shù)據(jù)。 |
? |
RefreshData – 創(chuàng)建 ReferenceCacheDataPayload 并將其排入隊列以便異步處理,來刷新參考數(shù)據(jù)緩存中的過期數(shù)據(jù)。 |
ReferenceCacheDataPayload 類
該類派生自 Payload 類,同時也包含 ReferenceDataDefinition。該組件是有關(guān)更新參考緩存數(shù)據(jù)所需的參考數(shù)據(jù)的元數(shù)據(jù)。
類成員
以下部分(“方法”和“屬性”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請參閱該應(yīng)用程序塊中隨附的幫助文件。
方法
UpdateDataToReturn – 更新 Payload 中從遠程服務(wù)返回的數(shù)據(jù)。
屬性
? |
DataDefinition – 返回來自創(chuàng)建 Payload 的參考數(shù)據(jù)緩存項目的 ReferenceDataDefinition 值。 |
? |
IsRefreshMessage – 布爾值,表示是否已創(chuàng)建 Payload 來刷新參考數(shù)據(jù)項目。 |
緩存塊和存儲提供程序
“參考數(shù)據(jù)管理”子系統(tǒng)使用 Caching Application Block 來存儲緩存的數(shù)據(jù)。緩存塊支持在配置文件中定義多個提供程序,但在配置文件中只能啟用其中一個提供程序。
如果配置文件中的提供程序發(fā)生更改,則該緩存塊將使用新的提供程序來存儲緩存數(shù)據(jù)。該塊沒有將數(shù)據(jù)從以前的數(shù)據(jù)存儲區(qū)移到新數(shù)據(jù)存儲區(qū)的內(nèi)置功能。這個功能必須由開發(fā)人員添加。
除了 Caching Application Block 附帶的提供程序之外,Offline Application Block 還包括一個獨立的存儲緩存提供程序。這些提供程序的說明如下:
? |
IsolatedStorageCacheProvider – 將緩存數(shù)據(jù)存儲在支持 .NET 的獨立存儲區(qū)中。當(dāng)項目被物理持久保存時,它針對每個緩存項目使用一個文件。文件的名稱對應(yīng)于用戶指定的緩存項。在 Offline Application Block 中,緩存項將用作文件名,這就為緩存項創(chuàng)建了一個約束:緩存項不能包含被文件系統(tǒng)特殊處理的符號,例如,“\”、“*”或“?”。該塊可確保應(yīng)用程序開發(fā)人員所使用的任何項目名稱都對應(yīng)于“獨立存儲”中的有效文件名,否則它將引發(fā)一個異常。 |
? |
Caching Application Block Providers – 包括用于 SQL Server、內(nèi)存存儲和內(nèi)存映射文件存儲的緩存存儲提供程序。有關(guān)詳細(xì)信息,請參閱 Caching Application Block。 |
實用工具服務(wù)
“實用工具服務(wù)”提供后臺服務(wù),例如多提供程序配置處理程序、配置程序和生成器。生成器用于創(chuàng)建特定類的實例。生成器使用配置程序從配置文件中讀取相關(guān)信息。
MultiProviderConfigHandler 類
Offline Application Block 提供為配置文件中的單個配置區(qū)段定義多個提供程序的能力。當(dāng)您管理多個類型的數(shù)據(jù)存儲區(qū)并需要關(guān)聯(lián)來自這些不同數(shù)據(jù)存儲區(qū)的數(shù)據(jù)時,多個提供程序非常有用。在這種情況下,您需要通過編程手段在讀取數(shù)據(jù)和關(guān)聯(lián)數(shù)據(jù)時逐個啟用或禁用存儲區(qū)。這些區(qū)段中只有一個必須通過將 enabled 屬性設(shè)置為 true 來啟用。MultiProviderConfigHandler 類負(fù)責(zé)讀取配置信息,并確保滿足該條件。它實現(xiàn)接口 IConfigurationSectionHandler,并實現(xiàn)該接口強制的 Create 方法。
類成員
以下部分(“方法”)介紹了該類中最重要的成員。有關(guān)詳細(xì)信息,請參閱該應(yīng)用程序塊中隨附的幫助文件。
方法
Create – 從配置文件 (App.config) 中讀取指定配置區(qū)段,并返回該類的客戶端可以使用的 System.Collections.Hashtable 中的信息。
如果您計劃在設(shè)計中使用多個提供程序,則使用該類可以簡化您的代碼。
生成器
該應(yīng)用程序塊中的每個關(guān)鍵類都具有一個關(guān)聯(lián)的生成器類。生成器類抽象了從生成器類的客戶端創(chuàng)建關(guān)聯(lián)類的實例的復(fù)雜性。每個生成器類都使用 Builder 模式。
對于諸如 ConnectionManager、DataLoaderManager、ServiceAgentManager、QueueManager、Executor、ReferenceDataCache 和 DataLoaderManager 這樣的類,整個應(yīng)用程序只需要一個類的實例,因此可以將這些類創(chuàng)建為 Singleton。但是,Singleton 具有一個缺點,那就是會導(dǎo)致強耦合。這一點抑制了塊體系結(jié)構(gòu)的優(yōu)點,從而鼓勵了可交互、可重復(fù)使用的代碼的開發(fā),這些代碼的類可單獨進行測試。包含生成器類的目的在于創(chuàng)建特定類的實例,而不是使用 Singleton。
OfflineBlockBuilder
OfflineBlockBuilder 類是應(yīng)用程序開發(fā)人員需要調(diào)用以實例化所有子系統(tǒng)的唯一類。它通過調(diào)用相應(yīng)的生成器類來完成。它是 Singleton,您可以使用該類的 Instance 屬性來訪問它。它將所有關(guān)鍵類公開為屬性。下面的列表包含了由 OfflineBlockBuilder 類創(chuàng)建的所有類:
? |
DataLoaderManager |
? |
ReferenceDataCache |
? |
ServiceAgentManager |
? |
ServiceAgentRegistry |
? |
ConnectionManager |
? |
PayloadConsumer(隊列所公開的接口,用于支持向隊列中添加項目所需的功能) |
OfflineBlockBuilder 類還支持啟動和停止所有子系統(tǒng)的 Start 和 Stop 方法。下面列出的是該類中最重要的成員。有關(guān)詳細(xì)信息,請參閱該應(yīng)用程序塊中隨附的幫助文件。
? |
Instance – 創(chuàng)建塊生成器的實例。 |
? |
Start – 啟動塊。 |
? |
Stop – 停止塊。 |
? |
Dispose – 停止塊并處理 OfflineBlockBuilder。 |
ConnectionManagerBuilder 類
ConnectionManagerBuilder 類可構(gòu)建 ConnectionManager 類并將 ConnectionManager 作為一個屬性公開。
ServiceAgentManagerBuilder 類
ServiceAgentManagerBuilder 類可構(gòu)建 ServiceAgentManager 類并將 ServiceAgentManager 作為一個屬性公開。此外,它還可以創(chuàng)建 ServiceAgentRegistry 類的一個對象,并將其作為一個屬性公開。
QueueManagerBuilder 類
QueueManagerBuilder 類可構(gòu)建 QueueManager 類并將 QueueManager 作為一個屬性公開。通過使用 QueueManagerConfigurator 類,該類可以從配置文件中獲得隊列存儲提供程序的信息。它可創(chuàng)建在配置文件中指定的隊列存儲提供程序的實例,并在創(chuàng)建過程中將其傳遞到 QueueManager。
ExecutorBuilder 類
ExecutorBuilder 類可構(gòu)建 Executor 類并將 Executor 作為一個屬性公開。
ReferenceDataCacheBuilder 類
ReferenceDataCacheBuilder 類可構(gòu)建 IReferenceDataCache 接口類型,并將 IReferenceDataCache 類型對象作為一個屬性公開。
DataLoaderManagerBuilder 類
DataLoaderManagerBuilder 類可構(gòu)建 DataLoaderManager 類并將 DataLoaderManager 作為一個屬性公開。
參考數(shù)據(jù)緩存工作流
本部分介紹使用 Offline Application Block 來下載、管理、刷新和緩存參考數(shù)據(jù)的工作流。
下載參考緩存數(shù)據(jù)
如前所述,若要使應(yīng)用程序在脫機狀態(tài)下工作,必須下載參考數(shù)據(jù)并將其緩存到客戶端上。下載參考數(shù)據(jù)是由應(yīng)用程序啟動的。根據(jù)連接狀態(tài),應(yīng)用程序可以決定是否啟動下載參考數(shù)據(jù)項目。在這方面,應(yīng)用程序塊不會強制執(zhí)行任何操作。
協(xié)作下載參考數(shù)據(jù)的組件包括由應(yīng)用程序開發(fā)人員創(chuàng)建的“應(yīng)用程序服務(wù)代理”、應(yīng)用程序塊中提供的 DataLoaderManager 類以及“消息數(shù)據(jù)管理”子系統(tǒng)。下列步驟演練了圖 2.6 中所示的過程。
應(yīng)用程序創(chuàng)建“應(yīng)用程序服務(wù)代理”的一個實例。“應(yīng)用程序服務(wù)代理”為參考緩存數(shù)據(jù)項目創(chuàng)建一個 ReferenceDataDefinition 對象。“應(yīng)用程序服務(wù)代理”指定與緩存項目相對應(yīng)的項、可選的過期策略以及 OnlineProxyContext 和 ServiceAgentContext。 “服務(wù)代理”實例化 DataLoaderManager,并為它提供對應(yīng)于需要下載的參考緩存數(shù)據(jù)項目的 ReferenceDataDefinition。 DataLoaderManager 使用 ReferenceDataDefinition 創(chuàng)建 ReferenceCacheDataPayload 的一個實例,并使用“信息數(shù)據(jù)管理”子系統(tǒng)將其排入隊列以進行異步處理。 “消息數(shù)據(jù)管理”子系統(tǒng)的消息處理會導(dǎo)致從遠程服務(wù)檢索參考緩存數(shù)據(jù)項目。“聯(lián)機代理”將參考數(shù)據(jù)添加到參考緩存中。 結(jié)果被返回給特定的“應(yīng)用程序服務(wù)代理”。

圖 2.6.排隊參考數(shù)據(jù)加載請求
刷新參考緩存數(shù)據(jù)
下載的參考緩存數(shù)據(jù)會在一段時間后變舊。該應(yīng)用程序塊可提供為每個參考緩存數(shù)據(jù)項目指定過期策略的功能。根據(jù)該過期策略,應(yīng)用程序塊可刷新參考緩存數(shù)據(jù)項目。當(dāng)參考緩存數(shù)據(jù)項目過期后,該應(yīng)用程序塊會根據(jù) Caching Application Block 的 CacheManager 組件引發(fā)的事件來啟動刷新。
協(xié)作刷新參考緩存數(shù)據(jù)的組件包括 CacheManager、ReferenceDataCache、ReferenceDataRefreshController 和 DataLoaderManager。
當(dāng)參考緩存數(shù)據(jù)項目下載并添加到緩存中時,如前一部分“下載參考緩存數(shù)據(jù)”中的說明,您可以在參考數(shù)據(jù)定義中為緩存項目指定過期策略。除此之外,當(dāng)某個項目過期時,Caching Application Block 還允許指定回調(diào)方法(委派)。當(dāng)參考緩存數(shù)據(jù)項目存儲在緩存中時,如果項目過期,ReferenceDataRefreshController 類的 CacheItemExpiredCallback 方法被指定為回調(diào)方法。圖 2.7 展示了說明下列步驟的過程:
? |
CacheManager 監(jiān)視緩存項目是否過期。當(dāng)某個項目過期時,緩存管理器將調(diào)用的 ReferenceDataRefreshController 的指定 CacheItemExpiredCallback 方法。 |
? |
如果緩存項目已經(jīng)過期,則基礎(chǔ) Caching Application Block 將從緩存中刪除該項目。在啟動下載前,ReferenceDataRefreshController 將該項目添加回緩存中 — 這樣做可防止信息丟失。 |
? |
然后,ReferenceDataRefreshController 通過 DataLoaderManager 來啟動下載參考數(shù)據(jù)項目。 |
? |
DataLoaderManager 使用 ReferenceDataDefinition 來創(chuàng)建 ReferenceCacheDataPayload 的實例。然后,它使用“消息數(shù)據(jù)管理”子系統(tǒng)的類 QueueManager 將 ReferenceCacheDataPayload 的對象作為消息排入隊列以進行異步處理。 |
? |
“消息數(shù)據(jù)管理”子系統(tǒng)的消息處理會導(dǎo)致從遠程服務(wù)檢索參考緩存數(shù)據(jù)項目。“聯(lián)機代理”將參考數(shù)據(jù)添加到參考緩存中。 |
? |
結(jié)果被返回給特定的“應(yīng)用程序服務(wù)代理”。 |

圖 2.7.緩存項目過期并獲得刷新
根據(jù)設(shè)計,在“參考數(shù)據(jù)緩存”中刷新參考數(shù)據(jù)時,Offline Application Block 不會將事件提交到應(yīng)用程序。如下面的說明所示,添加該功能是一項簡單的任務(wù)。
當(dāng)完成服務(wù)請求以及當(dāng)(且僅當(dāng))相同的“服務(wù)代理”可以由 Offline Application Block 回調(diào)時,請記住將事件提交到應(yīng)用程序。如果在刷新緩存中的數(shù)據(jù)時發(fā)生相同的情況,則必須創(chuàng)建一個長期的“服務(wù)代理”并在每次刷新數(shù)據(jù)時使用,而且還必須使該“服務(wù)代理”可用于該應(yīng)用程序,以便它可以注冊接收這些完成事件。該實現(xiàn)類似于 FailsafeServiceAgent 實現(xiàn)。
管理參考緩存數(shù)據(jù)
要管理參考緩存數(shù)據(jù),您必須以某種方式對其進行標(biāo)記,以便知道該數(shù)據(jù)是否需要刷新。數(shù)據(jù)可以標(biāo)記為 dirty、expired 或者兩者。根據(jù)標(biāo)記數(shù)據(jù)的方式,參考緩存處理數(shù)據(jù)的方式可能會更改。
如果數(shù)據(jù)為 dirty,則意味著它已經(jīng)在本地進行更改,但沒有在服務(wù)器上進行更改。一旦在服務(wù)器上進行更新,數(shù)據(jù)會標(biāo)記為 clean。請記住,我們沒有辦法知道消息何時在服務(wù)器上進行實際更新。它也可能在計劃批作業(yè)完成之后發(fā)生。同樣,如果數(shù)據(jù)更改過幾次,則直到發(fā)送所有更新請求之后,它才會標(biāo)記為 clean。
數(shù)據(jù)還可以在參考緩存中標(biāo)記為 expired。這意味著“緩存管理器”已經(jīng)確定緩存中的某個項目已經(jīng)過期,導(dǎo)致“緩存管理器”將其從緩存中刪除并對有關(guān)該過期項目的參考數(shù)據(jù)執(zhí)行一個回調(diào)方法。
理解參考緩存中的“臟”(dirty) 數(shù)據(jù)如何與“過期”(expired) 數(shù)據(jù)進行交互非常重要。
? |
既不是“臟”又不是“過期”的數(shù)據(jù)被視為干凈的數(shù)據(jù)。如果該數(shù)據(jù)過期,它就會被刷新。 |
? |
如果已標(biāo)記為 expired 的數(shù)據(jù)再次過期,將不會為其執(zhí)行另一次刷新操作。 |
? |
如果數(shù)據(jù)過期且標(biāo)記為 dirty,則在參考緩存中將數(shù)據(jù)標(biāo)記為 clean 之前,將不會刷新該數(shù)據(jù)。原因是,使數(shù)據(jù)在本地變臟的操作為數(shù)據(jù)提供了比刷新后的數(shù)據(jù)更好、更新的值。因此,刷新消息的結(jié)果可以忽略。 |
緩存參考數(shù)據(jù)
Caching Application Block 允許您為緩存的項目指定特定的元數(shù)據(jù)。這包括過期策略以及當(dāng)項目過期時的回調(diào)方法。Offline Application Block 必須支持其他元數(shù)據(jù),才能指定組件的上下文信息。當(dāng)某個項目過期時,這些組件會檢索參考數(shù)據(jù)。創(chuàng)建 ReferenceDataDefinition 類以存儲擴展的元數(shù)據(jù)。ReferenceDataDefinition 類還包含一個到實際參考緩存項目的項。除了在需要時傳遞該信息的能力外,當(dāng)您需要檢查有關(guān)參考緩存項目的元數(shù)據(jù)時,它還提供了一個優(yōu)化,這是因為不需要反序列化整個緩存項目。
當(dāng)某個項目過期時,Caching Application Block 會在通知應(yīng)用程序之前從緩存中永久性的刪除該項目。這對于以脫機模式運行的應(yīng)用程序來說有幾個含義。如果刪除了緩存的項目,應(yīng)用程序就無法使用緩存中的數(shù)據(jù)來繼續(xù)操作。由于 ReferenceDataDefinition 和緩存項目都被緩存,如果它們兩者都從緩存中被刪除,就無法檢索它們并將它們添加回參考緩存數(shù)據(jù)中。要克服這一限制,可以在緩存的存儲架構(gòu)中添加一個間接層。
使用該架構(gòu),過期在第一個間接層上指定。當(dāng)該項目過期時,將出現(xiàn)一個帶有該項的值的通知。然后,為 ReferenceDataDefinition 和參考緩存項目自動生成項。這樣,應(yīng)用程序就可以繼續(xù)訪問它們。ReferenceDataRefreshController 接收通知并使用 DataLoaderManager 來刷新數(shù)據(jù)。DataLoaderManager 組件在開始下載前添加第一級架構(gòu)。
Caching Application Block 已經(jīng)提供了內(nèi)存緩存、內(nèi)存映射文件緩存以及 SQL 數(shù)據(jù)庫緩存。Offline Application Block 構(gòu)建在該基礎(chǔ)結(jié)構(gòu)上,通過包括獨立存儲緩存提供程序來提供緩存支持。該提供程序允許應(yīng)用程序?qū)⑻囟ㄓ诓煌脩舻臄?shù)據(jù)存儲在運行智能客戶端應(yīng)用程序的客戶端計算機上的不同位置。
Caching Application Block 支持對緩存數(shù)據(jù)進行加密和解密。Offline Application Block 利用該功能根據(jù)配置信息來確保緩存數(shù)據(jù)的安全。
請求和響應(yīng)往返
本部分說明了在使用 Offline Application Block 的應(yīng)用程序中,請求和響應(yīng)的往返過程是如何實現(xiàn)的。下列步驟說明了圖 2.8 中闡釋的往返行程。
? |
應(yīng)用程序的“用戶界面控制器”(UIC) 通常會創(chuàng)建一個執(zhí)行該任務(wù)的特定“應(yīng)用程序服務(wù)代理”的實例。“應(yīng)用程序服務(wù)代理”將創(chuàng)建 Payload 以便執(zhí)行該任務(wù)。Payload 包含執(zhí)行該任務(wù)所需的所有數(shù)據(jù)。此外,Payload 還包含有關(guān) OnlineProxyContext 和 ServiceAgentContext 中組件的所有上下文信息。 |
? |
使用 QueueManager 類的 Enqueue 方法,“應(yīng)用程序服務(wù)代理”可將 Payload 排入隊列。在使用已配置的隊列存儲提供程序?qū)?Payload 存儲到隊列之前,Enqueue 方法將 Payload 封裝在 QueueMessage 類中。 |
? |
如果應(yīng)用程序處于聯(lián)機狀態(tài),Executor(運行在獨立線程上)將使用 QueueManager 類的 Dequeue 方法從隊列中獲取 QueueMessage。然后,它從 QueueMessage 中檢索 Payload。 |
? |
Executor 從對應(yīng)于“聯(lián)機狀態(tài)”的 Payload 中檢索 OnlineProxyContext。通過反射使用 OnlineProxyContext 信息,它可執(zhí)行指定的“聯(lián)機代理”方法。“聯(lián)機代理”與遠程服務(wù)進行交互以完成該操作。“聯(lián)機代理”還將緩存結(jié)果、執(zhí)行所有請求后期處理,并處理公共事務(wù)。 |
? |
在執(zhí)行請求后,“聯(lián)機代理”將結(jié)果填充到 Payload 中。然后,Executor 將 Payload 返回到 ServiceAgentManager。 |
? |
ServiceAgentManager 類從 Payload 中檢索對應(yīng)于“應(yīng)用程序服務(wù)代理”實例的 GUID。使用 GUID,它可以在服務(wù)代理注冊表中找到“應(yīng)用程序服務(wù)代理”。如果有對應(yīng)于 GUID 的“應(yīng)用程序服務(wù)代理”(原始“應(yīng)用程序服務(wù)代理”),ServiceAgentManager 會檢索原始的“應(yīng)用程序服務(wù)代理”以返回結(jié)果;否則,FailsafeServiceAgent 類將用作“聯(lián)機代理”執(zhí)行過程中處理錯誤的最后手段。 |
? |
“服務(wù)代理管理器”將檢索“應(yīng)用程序服務(wù)代理”,然后使用 Payload 中的 ServiceAgentContext 信息來調(diào)用回調(diào)方法。該調(diào)用會在其他線程上進行。“應(yīng)用程序服務(wù)代理”將適當(dāng)?shù)靥幚斫Y(jié)果。 |

圖 2.8.請求和響應(yīng)往返
應(yīng)用程序設(shè)計注意事項
到目前為止,本章已經(jīng)闡述了 Offline Application Block 的設(shè)計。本部分介紹有關(guān)智能客戶端應(yīng)用程序設(shè)計的注意事項。
服務(wù)代理的生命周期
“應(yīng)用程序服務(wù)代理”是生存期很長的對象,這意味著它們至少可以在消息到其遠程業(yè)務(wù)功能或服務(wù)的往返時間內(nèi)存在。(如果關(guān)閉應(yīng)用程序,則內(nèi)存中的“應(yīng)用程序服務(wù)代理”會被刷新。)每個“應(yīng)用程序服務(wù)代理”都會自動向“服務(wù)代理注冊表”進行注冊,并由唯一的 GUID 標(biāo)識。這個 GUID 用于將來自遠程業(yè)務(wù)功能(服務(wù))的響應(yīng)返回到原始的“應(yīng)用程序服務(wù)代理”。如果原始的“應(yīng)用程序服務(wù)代理”(由其唯一的 GUID 標(biāo)識)不再可用,則“服務(wù)代理管理器”將使用 FailsafeServiceAgent 來報告錯誤。
在配置文件中定義多個提供程序
在配置文件中,您可以為單個配置區(qū)段定義多個提供程序。提供程序區(qū)段下面未啟用的提供程序或元素可以選擇性地在配置中使用 enabled="false",或者它們可以完全忽略已啟用的屬性。確保只啟用一個提供程序的算法封裝在 MultiProviderConfigHandler 類中。要在運行時允許動態(tài)更改配置文件,您可以使用 Configuration Management Application Block。
有關(guān)詳細(xì)信息,請參閱第 4 章中有關(guān)配置文件的部分。
線程
該塊可在其子系統(tǒng)中創(chuàng)建幾個內(nèi)部線程。它們包括:
? |
一個從應(yīng)用程序代碼中異步處理已排隊消息的線程。 |
? |
一個輪詢連接狀態(tài)更改并通知已注冊的組件狀態(tài)發(fā)生更改的線程。 |
重要的是,從這些線程的其中一個調(diào)用的應(yīng)用程序代碼不能在該調(diào)用中進行長時間處理,以避免延遲塊代碼。例如,如果應(yīng)用程序的連接狀態(tài)發(fā)生更改,“連接管理器”將調(diào)用已注冊對該類的 ConnectionStateChangedEvent 關(guān)注的任意類。該調(diào)用在“連接管理器”的連接檢測線程中進行,因此由客戶端開始的任何長時間處理都會干擾“連接管理器”監(jiān)視是否存在后續(xù)的狀態(tài)更改。一般來說,事件處理代碼應(yīng)快速運行,并且不應(yīng)回調(diào)到塊代碼中。
數(shù)據(jù)協(xié)調(diào)
該塊不處理數(shù)據(jù)協(xié)調(diào)。這是客戶端代碼或遠程業(yè)務(wù)邏輯的責(zé)任。除了在“參考數(shù)據(jù)管理”部分中所述的“臟”或“過期”處理外,來自遠程業(yè)務(wù)邏輯的結(jié)果將在本地覆寫所有可用的信息。例如,如果應(yīng)用程序更新了某個客戶的電話號碼,那么該更改會排入隊列,之后發(fā)出請求,然后收到包含操作成功通知的結(jié)果。但是,如果最終在服務(wù)器端更新該信息需要幾小時或幾天時間,那么就存在這樣的風(fēng)險:在此期間向服務(wù)器發(fā)出的獲取客戶電話號碼的請求可能會返回舊值。這已經(jīng)超出了該塊的范圍。開發(fā)人員必須在應(yīng)用程序代碼或遠程業(yè)務(wù)邏輯中提供解決方案。
在獨立的進程中運行組件
Offline Application Block 設(shè)計為完全在單個進程中運行。但是,塊中的某些組件可能會在多個進程中運行。
Executor 是最佳選擇。您可以將其作為一個 Windows 服務(wù)運行,當(dāng)應(yīng)用程序本身關(guān)閉時允許它為掛起的消息隊列提供服務(wù)。以下步驟介紹了實現(xiàn)方法:
? |
在生成器類中為 Executor 組件更新創(chuàng)建邏輯。同時還必須更新主生成器類。 |
? |
消息經(jīng)過處理后返回的結(jié)果必須在聯(lián)機和脫機方案中處理(將其返回到應(yīng)用程序)。實現(xiàn)這一點可以采取幾種不同的方法:您可以創(chuàng)建一個共享位置(例如緩存),將應(yīng)用程序的結(jié)果存儲在其中。您還可以獲取它們或使用某些內(nèi)部處理通信機制(例如遠程處理),將結(jié)果返回應(yīng)用程序。 |
? |
“參考數(shù)據(jù)管理”和“消息數(shù)據(jù)管理”子系統(tǒng)必須能夠用于 Executor,以便能夠處理消息并更新緩存。這會影響到與應(yīng)用程序一起使用的隊列和緩存存儲提供程序,以及子系統(tǒng)本身的設(shè)計。 |
通過在獨立的進程中運行塊的一些組件,可以獲得較高的效率,包括為多個可能相關(guān)的應(yīng)用程序創(chuàng)建共享的緩存和隊列,以及創(chuàng)建同步消息數(shù)據(jù)和下載/刷新參考緩存數(shù)據(jù)的通用服務(wù)。但是,您還應(yīng)慎重考慮某些問題,例如緩存架構(gòu)、組件之間的通信以及任何與爭用相關(guān)的問題。
其他設(shè)計
Offline Application Block 的設(shè)計可使用異步行為來執(zhí)行消息。異步行為可防止在 UI 線程上執(zhí)行長時間操作,這樣就提供了更好的用戶體驗。
在某些情況下,如果網(wǎng)絡(luò)可靠并具有很高的帶寬,您可以考慮其他設(shè)計,例如,僅當(dāng)應(yīng)用程序脫機時,才會發(fā)生“應(yīng)用程序服務(wù)代理”將 Payload 排入隊列的情況。一旦應(yīng)用程序再次聯(lián)機,它將繞過 Offline Application Block 子系統(tǒng)而直接調(diào)用“聯(lián)機代理”。在處理請求后,“聯(lián)機代理”會將結(jié)果返回到“應(yīng)用程序服務(wù)代理”。這是 UI 線程上的同步調(diào)用,如果它是長時間運行的操作,則不建議使用,因為它可能會凍結(jié) UI。您可以通過調(diào)用其他線程(而不是 UI 線程)來進行優(yōu)化,并使用 .NET 中提供的異步支持。
提示 要在“服務(wù)代理”中避免使用 if-else 語句,您可以使用狀態(tài)模式來根據(jù)狀態(tài)作出有關(guān)處理的決定。
小結(jié)
Offline Application Block 的設(shè)計為滿足應(yīng)用程序以脫機模式工作的需要提供了核心基礎(chǔ)結(jié)構(gòu)。它由下列子系統(tǒng)組成:
? |
連接狀態(tài)管理 |
? |
服務(wù)代理管理 |
? |
消息數(shù)據(jù)管理 |
? |
參考數(shù)據(jù)管理 |
? |
實用工具服務(wù) |
“連接狀態(tài)管理”子系統(tǒng)的主要角色是檢測連接狀態(tài),并通知偵聽器有關(guān)任何狀態(tài)的變化。
“服務(wù)代理管理”子系統(tǒng)可實現(xiàn)下列功能
? |
維護“應(yīng)用程序服務(wù)代理”的注冊表 |
? |
包含負(fù)責(zé)在處理請求后將結(jié)果返回給“應(yīng)用程序服務(wù)代理”的組件 |
? |
提供應(yīng)用程序開發(fā)人員用于實現(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ù)據(jù)。通過允許加密和解密緩存的數(shù)據(jù),它還提供了安全存儲數(shù)據(jù)的能力。
“實用工具服務(wù)”子系統(tǒng)管理連接性和非池線程。