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