簡介
Microsoft 近期推出了一種用于生成集成應用程序的新平臺——Microsoft .NET 框架。.NET
框架允許開發人員使用任何編程語言迅速生成和部署 Web 服務和應用程序。Microsoft Intermediate Language
(MSIL) 和實時 (JIT) 編譯器使這種不依賴語言的框架得以實現。
與 .NET
框架同時面世的還有一種新的編程語言 C#(讀作“C sharp”)。C# 是一種簡單、新穎、面向對象和類型安全的編程語言。利用 .NET
框架和 C#(除 Microsoft? Visual Basic? 和 Managed C++ 之外),用戶可以編寫功能強大的
Microsoft Windows? 和 Web 應用程序及服務。本文提供了這樣的一個解決方案,它的重點是 .NET 框架和 C#
而不是編程語言。C# 語言的介紹可以在“ C# 簡介和概述(英文)”找到。
近期的文章“MSMQ:可伸縮、高可用性的負載平衡解
決方案(英文)”介紹了一種解決方案,用于高可用性消息隊列 (MSMQ) 的可伸縮負載平衡解決方案體系結構。此解決方案中涉及了一種將
Windows 服務用作智能消息路由器的開發方案。這樣的解決方案以前只有 Microsoft Visual C++? 程序員才能實現,而
.NET 框架的出現改變了這種情況。從下面的解決方案中,您可以看到這一點。
.NET 框架應用程序
這里介紹
的解決方案是一種用來處理若干消息隊列的 Windows
服務;其中每個隊列都是由多個線程進行處理(接收和處理消息)。處理程序使用循環法技術或應用程序特定值(消息 AppSpecific
屬性)從目的隊列列表中路由消息,并使用消息屬性來調用組件方法。(示例進程也屬于這種情況。)在后一種情況下,組件的要求是它能夠實現給定的接口
IWebMessage。要處理錯誤,應用程序需要將不能處理的消息發送到錯誤隊列中。
消息應用程序的結構與以前的活動模板庫
(ATL) 應用程序相似,它們之間的主要不同在于用于管理服務的代碼的封裝和 .NET 框架組件的使用。要創建 Windows 服務,.NET
框架用戶僅僅需要創建一個從 ServiceBase(來自 System.ServiceControl 程序集)繼承的類。這毫不奇怪,因為
.NET 框架是面向對象的。
應用程序結構
應用程序中主要的類是 ServiceControl,它是從 ServiceBase 繼承的。因而,它必須實現 OnStart 和
OnStop 方法,以及可選的 OnPause 和 OnContinue 方法。事實上,類是在靜態方法 Main 內構造的:
using System; using System.ServiceProcess;
public class ServiceControl: ServiceBase { // 創建服務對象的主入口點 public static void Main() { ServiceBase.Run(new ServiceControl()); }
// 定義服務參數的構造對象 public ServiceControl() { CanPauseAndContinue = true; ServiceName = "MSDNMessageService"; AutoLog = false; }
protected override void OnStart(string[] args) {...} protected override void OnStop() {...} protected override void OnPause() {...} protected override void OnContinue() {...} } |
ServiceControl 類創建一系列 CWorker 對象,即,為需要處理的每個消息隊列創建 CWorker
類的一個實例。根據定義中處理隊列所需的線程數目,CWorker 類依次創建了一系列的 CWorkerThread
對象。CWorkerThread 類創建的一個處理線程將執行實際的服務工作。
使用 CWorker 和 CWorkerThread 類的主要目的是確認服務控件 Start、Stop、Pause 和 Continue 命令。因為這些進程必須是無阻塞的,命令操作最終將在后臺處理線程上執行。
CWorkerThread 是一個抽象類,被 CWorkerThreadAppSpecific
、CWorkerThreadRoundRobin 和 CWorkerThreadAssembly
繼承。這些類以不同的方式處理消息。前兩個類通過給另一隊列發送消息來處理消息(其不同之處在于確定接收隊列路徑的方式),最后一個類則使用消息屬性來調
用組件方法。
.NET 框架內部的錯誤處理是以基類 Exception
為基礎的。當系統引發或捕獲錯誤時,這些錯誤必須是從 Exception 中導出的類。CWorkerThreadException
類就是這樣一種實現,它通過附加額外屬性(用于定義服務是否應繼續運行)來擴展基類。
最后,應用程序包含兩種結構。這些值類型定義了輔助進程或線程的運行時參數,以簡化 CWorker 和 CWorkerThread 對象的結構。使用值類型結構(而不是引用類型類)能夠確保這些運行時參數維護的是數值(而不是引用)。
IWebMessage 接口
CWorkerThread 的實現之一是一個調用組件方法的類。這個名為 CWorkerThreadAssembly 的類使用 IWebMessage 接口來定義服務和組件之間的約定。
與當前版本的 Microsoft Visual Studio? 不同,C# 接口可以在任何語言中顯式定義,而不需要創建和編譯 IDL 文件。C# IWebMessage 接口的定義如下:
public interface IWebMessage { WebMessageReturn Process(string sMessageLabel, string sMessageBody, int iAppSpecific); void Release(); } |
ATL 代碼中的 Process 方法是為處理消息而指定的。Process 方法的返回代碼定義為枚舉類型 WebMessageReturn:
public enum WebMessageReturn { ReturnGood, ReturnBad, ReturnAbort } |
枚舉的定義如下:Good 表示繼續處理,Bad 表示將消息寫入錯誤隊列,Abort 表示終止處理。Release
方法為服務提供了輕松清除類實例的途徑。因為僅在垃圾回收的過程中才調用類實例的析構函數,所以確保所有占用昂貴資源(例如數據庫連接)的類都有一個能夠
在析構之前被調用的方法,用來釋放這些資源,這是一種非常好的構思。
名稱空間
在這里先簡單介紹一下名稱空間。名稱空間允許在內部和外部表示中將應用程序組織成為邏輯元素。服務內的所有代碼都包含在
MSDNMessageService.Service
名稱空間內。盡管服務代碼包含在若干文件中,但是由于它們包含在同一名稱空間中,因此用戶不需要引用其他文件。
由于 IWebMessage 接口包含在 MSDNMessageService.Interface 名稱空間中,因此使用此接口的線程類具有一個接口名稱空間。
服務類
應用程序的目的是監視和處理消息隊列,每一隊列在收到消息時都執行不同的進程。應用程序是作為 Windows 服務來實現的。
ServiceBase 類
如前所述,服務的基本結構是從 ServiceBase 繼承的類。重要的方法包括 OnStart、OnStop、OnPause 和
OnContinue,每一個替代方法都與一個服務控制操作直接對應。OnStart 方法的目的是創建 CWorker 對象,而 CWorker
類又創建 CWorkerThread 對象,然后在該對象中創建執行服務工作的線程。
服務的運行時配置(以及 CWorker 和 CWorkerThread 對象的屬性)是在基于 XML 的配置文件中維護的。它的名稱與創建的 .exe 文件相同,但帶有一個 .cfg 后綴。配置示例如下:
<?xml version="1.0"?> <configuration> <ProcessList> <ProcessDefinition ProcessName="Worker1" ProcessDesc="Message Worker with 2 Threads" ProcessType="AppSpecific" ProcessThreads="2" InputQueue=".\private$\test_load1" ErrorQueue=".\private$\test_error"> <OutputList> <OutputDefinition OutputName=".\private$\test_out11" /> <OutputDefinition OutputName=".\private$\test_out12" /> </OutputList> </ProcessDefinition> <ProcessDefinition ProcessName="Worker2" ProcessDesc="Assembly Worker with 1 Thread" ProcessType="Assembly" ProcessThreads="1" InputQueue=".\private$\test_load2" ErrorQueue=".\private$\test_error"> <OutputList> <OutputDefinition OutputName="C:\MSDNMessageService\MessageExample.dll" /> <OutputDefinition OutputName="MSDNMessageService.MessageSample.ExampleClass"/> </OutputList> </ProcessDefinition> </ProcessList> </configuration> |
對此信息的訪問通過來自 System.Configuration 程序集的 ConfigManager 類來管理。靜態 Get
方法返回信息的集合,這些集合將被枚舉以獲得單個屬性。這些屬性集的設置決定了輔助對象的運行時特征。除了這一配置文件,您還應該創建定義 XML
文件結構的圖元文件,并在其中引用位于服務器 machine.cfg 配置文件中的圖元文件:
<?xml version ="1.0"?> <MetaData xmlns="x-schema:CatMeta.xms"> <DatabaseMeta InternalName="MessageService"> <ServerWiring Interceptor="Core_XMLInterceptor"/> <Collection InternalName="Process" PublicName="ProcessList" PublicRowName="ProcessDefinition" SchemaGeneratorFlags="EMITXMLSCHEMA"> <Property InternalName="ProcessName" Type="String" MetaFlags="PRIMARYKEY" /> <Property InternalName="ProcessDesc" Type="String" /> <Property InternalName="ProcessType" Type="Int32" DefaultValue="RoundRobin" > <Enum InternalName="RoundRobin" Value="0"/> <Enum InternalName="AppSpecific" Value="1"/> <Enum InternalName="Assembly" Value="2"/> </Property> <Property InternalName="ProcessThreads" Type="Int32" DefaultValue="1" /> <Property InternalName="InputQueue" Type="String" /> <Property InternalName="ErrorQueue" Type="String" /> <Property InternalName="OutputName" Type="String" /> <QueryMeta InternalName="All" MetaFlags="ALL" /> <QueryMeta InternalName="QueryByFile" CellName="__FILE" Operator="EQUAL" /> </Collection> <Collection InternalName="Output" PublicName="OutputList" PublicRowName="OutputDefinition" SchemaGeneratorFlags="EMITXMLSCHEMA"> <Property InternalName="ProcessName" Type="String" MetaFlags="PRIMARYKEY" /> <Property InternalName="OutputName" Type="String" MetaFlags="PRIMARYKEY" /> <QueryMeta InternalName="All" MetaFlags="ALL" /> <QueryMeta InternalName="QueryByFile" CellName="__FILE" Operator="EQUAL" /> </Collection> </DatabaseMeta> <RelationMeta PrimaryTable="Process" PrimaryColumns="ProcessName" ForeignTable="Output" ForeignColumns="ProcessName" MetaFlags="USECONTAINMENT"/> </MetaData> |
由于 Service 類必須維護一個已創建輔助對象的列表,因此使用了 Hashtable 集合,用于保持類型對象的名稱/數值對列表。Hashtable 不僅支持枚舉,還允許通過關鍵字來查詢值。在應用程序中,XML 進程名稱是唯一的關鍵字:
private Hashtable htWorkers = new Hashtable(); IConfigCollection cWorkers = ConfigManager.Get("ProcessList", new AppDomainSelector()); foreach (IConfigItem ciWorker in cWorkers) { WorkerFormatter sfWorker = new WorkerFormatter(); sfWorker.ProcessName = (string)ciWorker["ProcessName"]; sfWorker.ProcessDesc = (string)ciWorker["ProcessDesc"]; sfWorker.NumberThreads = (int)ciWorker["ProcessThreads"]; sfWorker.InputQueue = (string)ciWorker["InputQueue"]; sfWorker.ErrorQueue = (string)ciWorker["ErrorQueue"]; // 計算并定義進程類型 switch ((int)ciWorker["ProcessType"]) { case 0: sfWorker.ProcessType = WorkerFormatter.SFProcessType.ProcessRoundRobin; break; case 1: sfWorker.ProcessType = WorkerFormatter.SFProcessType.ProcessAppSpecific; break; case 2: sfWorker.ProcessType = WorkerFormatter.SFProcessType.ProcessAssembly; break; default: throw new Exception("Unknown Processing Type"); } // 執行更多的工作以讀取輸出信息 string sProcessName = (string)ciWorker["ProcessName"]; if (htWorkers.ContainsKey(sProcessName)) throw new ArgumentException("Process Name Must be Unique: " + sProcessName); htWorkers.Add(sProcessName, new CWorker(sfWorker)); } |
在這段代碼中沒有包含的主要信息是輸出數據的獲取。每一個進程定義中都有一組相應的輸出定義項。該信息是通過如下的簡單查詢讀取的:
string sQuery = "SELECT * FROM OutputList WHERE ProcessName=" + sfWorker.ProcessName + " AND Selector=appdomain://"; ConfigQuery qQuery = new ConfigQuery(sQuery); IConfigCollection cOutputs = ConfigManager.Get("OutputList", qQuery); int iSize = cOutputs.Count, iLoop = 0; sfWorker.OutputName = new string[iSize]; foreach (IConfigItem ciOutput in cOutputs) sfWorker.OutputName[iLoop++] = (string)ciOutput["OutputName"]; |
CWorkerThread 和 Cworker 類都有相應的服務控制方法,根據服務控制操作進行調用。由于 Hashtable 中引用了每一個 CWorker 對象,因此需要枚舉 Hashtable 的內容,以調用適當的服務控制方法:
foreach (CWorker cWorker in htWorkers.Values) cWorker.Start(); |
類似地,實現的 OnPause、OnContinue 和 OnStop 方法是通過調用 CWorker 對象上的相應方法來執行操作的。
CWorker 類
CWorker 類的主要功能是創建和管理 CWorkerThread 對象。Start、Stop、Pause 和 Continue
方法調用相應的 CWorkerThread 方法。實際的 CWorkerThread 對象是在Start 方法中創建的。與使用
Hashtable 管理輔助對象引用的 Service 類相似,CWorker 使用 ArrayList(簡單的動態數組)來維護線程對象的列表。
在這個數組內部,CWorker 類創建了 CWorkerThread 類的一個實現版本。CWorkerThread 類(將在下面討論)是一個必須繼承的抽象類。導出類定義了消息的處理方式:
aThreads = new ArrayList(); for (int idx=0; idx<sfWorker.NumberThreads; idx++) { WorkerThreadFormatter wfThread = new WorkerThreadFormatter(); wfThread.ProcessName = sfWorker.ProcessName; wfThread.ProcessDesc = sfWorker.ProcessDesc; wfThread.ThreadNumber = idx; wfThread.InputQueue = sfWorker.InputQueue; wfThread.ErrorQueue = sfWorker.ErrorQueue; wfThread.OutputName = sfWorker.OutputName; // 定義輔助類型,并將其插入輔助線程結構 CWorkerThread wtBase; switch (sfWorker.ProcessType) { case WorkerFormatter.SFProcessType.ProcessRoundRobin: wtBase = new CWorkerThreadRoundRobin(this, wfThread); break; case WorkerFormatter.SFProcessType.ProcessAppSpecific: wtBase = new CWorkerThreadAppSpecific(this, wfThread); break; case WorkerFormatter.SFProcessType.ProcessAssembly: wtBase = new CWorkerThreadAssembly(this, wfThread); break; default: throw new Exception("Unknown Processing Type"); } // 添加對數組的調用 aThreads.Insert(idx, wtBase); } |
一旦所有的對象都已創建,就可以通過調用每個線程對象的 Start 方法來啟動它們:
foreach(CWorkerThread cThread in aThreads) cThread.Start(); |
Stop、Pause 和 Continue 方法在 foreach 循環里執行的操作類似。Stop 方法具有如下的垃圾收集操作:
GC.SuppressFinalize(this); |
在類析構函數中將調用 Stop 方法,這樣,在沒有顯式調用 Stop 方法的情況下也可以正確地終止對象。如果調用了 Stop
方法,將不需要析構函數。SuppressFinalize 方法能夠防止調用對象的 Finalize 方法(析構函數的實際實現)。
CWorkerThread 抽象類
CWorkerThread 是一個由 CWorkerThreadAppSpecifc、CWorkerThreadRoundRobin 和
CWorkerThreadAssembly 繼承的抽象類。無論如何處理消息,隊列的大部分處理是相同的,所以 CWorkerThread
類提供了這一功能。這個類提供了抽象方法(必須被實際方法替代)以管理資源和處理消息。
類的工作再一次通過 Start、Stop、Pause 和 Continue 方法來實現。在 Start 方法中引用了輸入和錯誤隊列。在 .NET 框架中,消息由 System.Messaging 名稱空間處理:
// 嘗試打開隊列,并設置默認的讀寫屬性 MessageQueue mqInput = new MessageQueue(sInputQueue); mqInput.MessageReadPropertyFilter.Body = true; mqInput.MessageReadPropertyFilter.AppSpecific = true; MessageQueue mqError = new MessageQueue(sErrorQueue); // 如果使用 MSMQ COM,則將格式化程序設置為 ActiveX mqInput.Formatter = new ActiveXMessageFormatter(); mqError.Formatter = new ActiveXMessageFormatter(); |
一旦定義了消息隊列引用,即會創建一個線程用于實際的處理函數(稱為 ProcessMessages)。在 .NET 框架中,使用 System.Threading 名稱空間很容易實現線程處理:
procMessage = new Thread(new ThreadStart(ProcessMessages)); procMessage.Start(); |
ProcessMessages 函數是基于 Boolean 值的處理循環。當數值設為 False,處理循環將終止。因此,線程對象的 Stop 方法只設置這一 Boolean 值,然后關閉打開的消息隊列,并加入帶有主線程的線程:
// 加入服務線程和處理線程 bRun = false; procMessage.Join(); // 關閉打開的消息隊列 mqInput.Close(); mqError.Close(); |
Pause 方法只設置一個 Boolean 值,使處理線程休眠半秒鐘:
if (bPause) Thread.Sleep(500); |
最后,每一個 Start、Stop、Pause 和 Continue 方法將調用抽象的 OnStart、OnStop、OnPause 和 OnContinue 方法。這些抽象方法為實現的類提供了掛鉤,以捕獲和釋放所需的資源。
ProcessMessages 循環具有如下基本結構:
1、接收 Message。
2、如果 Message 具有成功的 Receive,則調用抽象 ProcessMessage 方法。
3、如果 Receive 或 ProcessMessage 失敗,將 Message 發送至錯誤隊列中。
Message mInput; try { // 從隊列中讀取,并等候 1 秒 mInput = mqInput.Receive(new TimeSpan(0,0,0,1)); } catch (MessageQueueException mqe) { // 將消息設置為 null mInput = null; // 查看錯誤代碼,了解是否超時 if (mqe.ErrorCode != (-1072824293) ) //0xC00E001B { // 如果未超時,發出一個錯誤并記錄錯誤號 LogError("Error: " + mqe.Message); throw mqe; } } if (mInput != null) { // 得到一個要處理的消息,調用處理消息抽象方法 try { ProcessMessage(mInput); } // 捕獲已知異常狀態的錯誤 catch (CWorkerThreadException ex) { ProcessError(mInput, ex.Terminate); } // 捕獲未知異常,并調用 Terminate catch { ProcessError(mInput, true); } } |
ProcessError 方法將錯誤的消息發送至錯誤隊列。另外,它也可能引發異常來終止線程。如果ProcessMessage 方法引發了終止錯誤或 CWorkerThreadException 類型,它將執行此操作。
CworkerThread 導出類
任何從 CWorkerThread 中繼承的類都必須提供 OnStart、OnStop、OnPause、OnContinue 和
ProcessMessage 方法。OnStart 和 OnStop 方法獲取并釋放處理資源。OnPause 和 OnContinue
方法允許臨時釋放和重新獲取這些資源。ProcessMessage 方法應該處理消息,并在出現失敗事件時引發
CWorkerThreadException 異常。
由于 CWorkerThread 構造函數定義運行時參數,導出類必須調用基類構造函數:
public CWorkerThreadDerived(CWorker v_cParent, WorkerThreadFormatter v_wfThread) : base (v_cParent, v_wfThread) {} |
導出類提供了兩種類型的處理:將消息發送至另一隊列,或者調用組件方法。接收和發送消息的兩種實現使用了循環技術或應用程序偏移(保留在消息
AppSpecific 屬性中),作為使用哪一隊列的決定因素。此方案中的配置文件應該包括隊列路徑的列表。實現的 OnStart 和
OnStop 方法應該打開和關閉對這些隊列的引用:
iQueues = wfThread.OutputName.Length; mqOutput = new MessageQueue[iQueues]; for (int idx=0; idx<iQueues; idx++) { mqOutput[idx] = new MessageQueue(wfThread.OutputName[idx]); mqOutput[idx].Formatter = new ActiveXMessageFormatter(); } |
在這些方案中,消息的處理很簡單:將消息發送必要的輸出隊列。在循環情況下,這個進程為:
try { mqOutput[iNextQueue].Send(v_mInput); } catch (Exception ex) { // 如果錯誤強制終止異常 throw new CWorkerThreadException(ex.Message, true); } // 計算下一個隊列號 iNextQueue++; iNextQueue %= iQueues; |
后一種調用帶消息參數的組件的實現方法比較有趣。ProcessMessage 方法使用 IWebMessage 接口調入一個 .NET 組件。OnStart 和 OnStop 方法獲取和釋放此組件的引用。
此方案中的配置文件應該包含兩個項目:完整的類名和類所在文件的位置。按照 IWebMessage 接口中的定義,在組件上調用 Process 方法。
要獲取對象引用,需要使用 Activator.CreateInstance 方法。此函數需要一個程序集類型。在這里,它是從程序集文件路徑和類名中導出的。一旦獲取對象引用,它將被放入合適的接口:
private IWebMessage iwmSample; private string sFilePath, sTypeName; // 保存程序集路徑和類型名稱 sFilePath = wfThread.OutputName[0]; sTypeName = wfThread.OutputName[1]; // 獲取對必要對象的引用 Assembly asmSample = Assembly.LoadFrom(sFilePath); Type typSample = asmSample.GetType(sTypeName); object objSample = Activator.CreateInstance(typSample); // 定義給對象的必要接口 iwmSample = (IWebMessage)objSample;
獲取對象引用后,ProcessMessage 方法將在 IWebMessage 接口上調用 Process 方法:
WebMessageReturn wbrSample; try { // 定義方法調用的參數 string sLabel = v_mInput.Label; string sBody = (string)v_mInput.Body; int iAppSpecific = v_mInput.AppSpecific; // 調用方法并捕捉返回代碼 wbrSample = iwmSample.Process(sLabel, sBody, iAppSpecific); } catch (InvalidCastException ex) { // 如果在消息內容中發生錯誤,則強制發出一個非終止異常 throw new CWorkerThreadException(ex.Message, false); } catch (Exception ex) { // 如果錯誤調用程序集,則強制發出終止異常 throw new CWorkerThreadException(ex.Message, true); } // 如果沒有錯誤,則檢查對象調用的返回狀態 switch (wbrSample) { case WebMessageReturn.ReturnBad: throw new CWorkerThreadException ("Unable to process message: Message marked bad", false); case WebMessageReturn.ReturnAbort: throw new CWorkerThreadException ("Unable to process message: Process terminating", true); default: break; } |
提供的示例組件將消息正文寫入數據庫表。如果捕獲到嚴重數據庫錯誤,您可能希望終止處理過程,但是在這里,僅僅將消息標記為錯誤的消息。
由于此示例中創建的類實例可能會獲取并保留昂貴的數據庫資源,所以用 OnPause 和 OnContinue 方法釋放和重新獲取對象引用。
CworkerThread 導出類
任何從 CWorkerThread 中繼承的類都必須提供 OnStart、OnStop、OnPause、OnContinue 和
ProcessMessage 方法。OnStart 和 OnStop 方法獲取并釋放處理資源。OnPause 和 OnContinue
方法允許臨時釋放和重新獲取這些資源。ProcessMessage 方法應該處理消息,并在出現失敗事件時引發
CWorkerThreadException 異常。
由于 CWorkerThread 構造函數定義運行時參數,導出類必須調用基類構造函數:
public CWorkerThreadDerived(CWorker v_cParent, WorkerThreadFormatter v_wfThread) : base (v_cParent, v_wfThread) {} |
導出類提供了兩種類型的處理:將消息發送至另一隊列,或者調用組件方法。接收和發送消息的兩種實現使用了循環技術或應用程序偏移(保留在消息
AppSpecific 屬性中),作為使用哪一隊列的決定因素。此方案中的配置文件應該包括隊列路徑的列表。實現的 OnStart 和
OnStop 方法應該打開和關閉對這些隊列的引用:
iQueues = wfThread.OutputName.Length; mqOutput = new MessageQueue[iQueues]; for (int idx=0; idx<iQueues; idx++) { mqOutput[idx] = new MessageQueue(wfThread.OutputName[idx]); mqOutput[idx].Formatter = new ActiveXMessageFormatter(); } |
在這些方案中,消息的處理很簡單:將消息發送必要的輸出隊列。在循環情況下,這個進程為:
try { mqOutput[iNextQueue].Send(v_mInput); } catch (Exception ex) { // 如果錯誤強制終止異常 throw new CWorkerThreadException(ex.Message, true); } // 計算下一個隊列號 iNextQueue++; iNextQueue %= iQueues; |
后一種調用帶消息參數的組件的實現方法比較有趣。ProcessMessage 方法使用 IWebMessage 接口調入一個 .NET 組件。OnStart 和 OnStop 方法獲取和釋放此組件的引用。
此方案中的配置文件應該包含兩個項目:完整的類名和類所在文件的位置。按照 IWebMessage 接口中的定義,在組件上調用 Process 方法。
要獲取對象引用,需要使用 Activator.CreateInstance 方法。此函數需要一個程序集類型。在這里,它是從程序集文件路徑和類名中導出的。一旦獲取對象引用,它將被放入合適的接口:
private IWebMessage iwmSample; private string sFilePath, sTypeName; // 保存程序集路徑和類型名稱 sFilePath = wfThread.OutputName[0]; sTypeName = wfThread.OutputName[1]; // 獲取對必要對象的引用 Assembly asmSample = Assembly.LoadFrom(sFilePath); Type typSample = asmSample.GetType(sTypeName); object objSample = Activator.CreateInstance(typSample); // 定義給對象的必要接口 iwmSample = (IWebMessage)objSample;
獲取對象引用后,ProcessMessage 方法將在 IWebMessage 接口上調用 Process 方法:
WebMessageReturn wbrSample; try { // 定義方法調用的參數 string sLabel = v_mInput.Label; string sBody = (string)v_mInput.Body; int iAppSpecific = v_mInput.AppSpecific; // 調用方法并捕捉返回代碼 wbrSample = iwmSample.Process(sLabel, sBody, iAppSpecific); } catch (InvalidCastException ex) { // 如果在消息內容中發生錯誤,則強制發出一個非終止異常 throw new CWorkerThreadException(ex.Message, false); } catch (Exception ex) { // 如果錯誤調用程序集,則強制發出終止異常 throw new CWorkerThreadException(ex.Message, true); } // 如果沒有錯誤,則檢查對象調用的返回狀態 switch (wbrSample) { case WebMessageReturn.ReturnBad: throw new CWorkerThreadException ("Unable to process message: Message marked bad", false); case WebMessageReturn.ReturnAbort: throw new CWorkerThreadException ("Unable to process message: Process terminating", true); default: break; } |
提供的示例組件將消息正文寫入數據庫表。如果捕獲到嚴重數據庫錯誤,您可能希望終止處理過程,但是在這里,僅僅將消息標記為錯誤的消息。
由于此示例中創建的類實例可能會獲取并保留昂貴的數據庫資源,所以用 OnPause 和 OnContinue 方法釋放和重新獲取對象引用。
文章來源:
http://www.tkk7.com/kuxiaoku/articles/94804.html
posted on 2007-01-19 00:13
苦笑枯 閱讀(275)
評論(0) 編輯 收藏 所屬分類:
C#