首頁  >  文章  >  後端開發  >  C#訊息佇列應用程式 -1

C#訊息佇列應用程式 -1

黄舟
黄舟原創
2016-12-17 16:56:311475瀏覽

簡介

  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屬性)從目的佇列列
表中路由訊息,並使用訊息屬性來呼叫元件方法。 (範例進程也屬於這種
情況。 )在後一種情況下,元件的要求是它能夠實現給定的介面IWeb
Message要處理錯誤,應用程式需要將不能處理的訊息傳送到錯誤佇列中。

  訊息應用程式的結構與先前的活動範本庫(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:MSDNMessageServiceMessage
   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。
     進程循環;
打破;
案例 1:
sfWorker.ProcessType = WorkerFormatter.SFProcessType。 ProcessAppSpecific;
打破; 案例 2: sfWorker.ProcessType = WorkerFormatter.SFProcessType。
組裝製程;
打破;
預設:

拋出新的 異常(“未知的處理類型”);
  }
  // 以讀取輸出資訊執行更多的工作
  字串 sProcessName = (string)ciWorker["進程名稱"];
如果 (htWorkers.ContainsKey(sProcessName))
拋出新的 ArgumentException(“進程名稱必須是唯一的:”
+ sProcessName);
  htWorkers.Add(sProcessName, new CWorker(sfWorker));
}

在becode中不包含的主要資訊是輸出資料的取得。每個程序定

義中都有一組對應的輸出定義項。此資訊是透過以下的簡單查詢讀取的:


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 = 新 字串[iSize];
foreach(cOutputs 中的 IConfigItem ciOutput)
  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的內容,更多相關文章請關注PHP中文網(www.php.cn)! 


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn