簡介
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:可伸縮、高可用性的Server Load Balancer解決方案(英文)”
介紹了一種解決方案,用於高可用性訊息佇列(MSMQ)的可伸縮Server Load Balancer
方案架構。此解決方案中涉及了一種將 Windows服務用作智能消
息路由器的開發方案。這樣的解決方案以前只有 Microsoft Visual C++
程式員才能實現,而 .NET 架構的出現改變了這種情況。從下面的解決方
案中,您可以看到這一點。
.NET 架構應用程式
這裡介紹的解決方案是一種用來處理若干訊息佇列的 Windows服務;
其中每個隊列都是由多個線程進行處理(接收和處理訊息)。處理常式使
用迴圈法技術或應用程式特定值(訊息 AppSpecific屬性)從目的隊列列
表中路由訊息,並使用訊息屬性來調用組件方法。(樣本進程也屬於這種
情況。)在後一種情況下,組件的要求是它能夠實現給定的介面IWeb
Message要處理錯誤,應用程式需要將不能處理的訊息發送到錯誤隊列中。
訊息應用程式的結構與以前的Active Template Library(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中匯出的類。CWorker
ThreadException 類就是這樣一種實現,它通過附加額外屬性(用於定義
服務是否應繼續運行)來擴充基類。
最後,應用程式套件組合含兩種結構。這些實值型別定義了輔助進程或線程的
運行時參數,以簡化 CWorker和 CWorkerThread對象的結構。使用實值型別
結構(而不是參考型別類)能夠確保這些運行時參數維護的是數值(而不
是引用)。
IWebMessage 介面
CWorkerThread 的實現之一是一個調用組件方法的類。這個名為
CWorkerThreadAssembly 的類使用 IWebMessage介面來定義服務和組件之
間的約定。
與目前的版本的 Microsoft Visual Studio?不同,C#介面可以在任何
語言中顯式定義,而不需要建立和編譯 IDL檔案。C# IWebMessage介面的
定義如下:
public interface IWebMessage
{
WebMessageReturn Process(string sMessageLabel, string sMessage
Body, int iAppSpecific);
void Release();
}
ATL 代碼中的 Process 方法是為處理訊息而指定的。Process 方法的返
回代碼定義為枚舉類型 WebMessageReturn:
public enum WebMessageReturn
{
ReturnGood,
ReturnBad,
ReturnAbort
}
枚舉的定義如下:Good表示繼續處理,Bad 表示將訊息寫入錯誤隊列,
Abort 表示終止處理。Release 方法為服務提供了輕鬆清除類執行個體的途徑。
因為僅在記憶體回收的過程中才調用類執行個體的解構函式,所以確保所有佔用
昂貴資源(例如資料庫連接)的類都有一個能夠在析構之前被調用的方法,
用來釋放這些資源,這是一種非常好的構思。
名稱空間
在這裡先簡單介紹一下名稱空間。名稱空間允許在內部和外部表格示中
將應用程式組織成為邏輯元素。服務內的所有代碼都包含在 MSDNMessage
Service.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\Message
Example.dll" /〉
〈OutputDefinition OutputName="MSDNMessageService.Message
Sample.ExampleClass"/〉
〈/OutputList〉
〈/ProcessDefinition〉
〈/ProcessList〉
〈/configuration〉
對此資訊的訪問通過來自 System.Configuration 程式集的 Config
Manager 類來管理。靜態 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" Meta
Flags="PRIMARYKEY" /〉
〈Property InternalName="ProcessDesc" Type="String" /〉
〈Property InternalName="ProcessType" Type="Int32" Default
Value="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" Meta
Flags="PRIMARYKEY" /〉
〈Property InternalName="OutputName" Type="String" Meta
Flags="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(簡單的動態數
組)來維護線程對象的列表。
以上就是C#訊息佇列應用程式 -1的內容,更多相關文章請關注topic.alibabacloud.com(www.php.cn)!