亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

C#消息隊列應用程序 -2

2019-11-18 19:50:17
字體:
來源:轉載
供稿:網友

  在這個數組內部,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、CWorkerThread
RoundRobin 和 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 循環具有如下基本結構:
●接收Message。
●如果Message具有成功的Receive,則調用抽象ProcessMessage方法。
●如果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方法引發了終止錯誤或 CWorker
ThreadException類型,它將執行此操作。

CworkerThread 導出類

  任何從 CWorkerThread中繼承的類都必須提供 OnStart、OnStop、On
Pause、OnContinue和 ProcessMessage 方法。OnStart 和 OnStop方法獲
取并釋放處理資源。OnPause 和 OnContinue 方法允許臨時釋放和重新獲
取這些資源。ProcessMessage方法應該處理消息,并在出現失敗事件時引
發 CWorkerThreadException 異常。

  由于 CWorkerThread構造函數定義運行時參數,導出類必須調用基類
構造函數:
public CWorkerThreadDerived(CWorker v_cParent, WorkerThread
Formatter 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 方法釋放和重新獲取對象引用。

檢測設備

  就象在所有優秀的應用程序中一樣,檢測設備用于監測應用程序的狀
態。。NET 框架大大簡化了將事件日志、性能計數器和 Windows管理檢測
設備(WMI )納入應用程序的過程。消息應用程序使用時間日志和性能計
數器,二者都是來自 System.Diagnostics 程序集。

  在 ServiceBase類中,您可以自動啟用事件日志。另外,ServiceBase
EventLog成員支持寫入應用程序事件日志:
EventLog.WriteEntry(sMyMessage, EventLogEntryType.Information);

  對于寫入事件日志而不是應用程序日志的應用程序,它能夠很容易地
創建和獲取 EventLog 資源的引用(正如在 CWorker類中所做的一樣),
并能夠使用 WriteEntry 方法記錄日志項:
private EventLog cLog;
string sSource = ServiceControl.ServiceControlName;
string sLog = "application";
// 查看源是否存在,如果不存在,則創建源
if (!EventLog.SourceExists(sSource))
  EventLog.CreateEventSource(sSource, sLog);
// 創建日志對象,并引用現在定義的源
cLog = new EventLog();
cLog.Source = sSource;
// 在日志中寫入條目,表明創建成功
cLog.WriteEntry("已成功創建", EventLogEntryType.Information);

  .NET 框架大大簡化了性能計數器。對于每一個處理線程、線程導出
的用戶和整個應用程序,這一消息應用程序都能提供計數器,用于跟蹤消
息數量和每秒鐘處理消息的數量。要提供此功能,您需要定義性能計數器
的類別,然后增加相應的計數器實例。

  性能計數器的類別在服務 OnStart方法中定義。這些類別代表兩種計
數器——消息總數和每秒鐘處理的消息數:
CounterCreationData[] cdMessage = new CounterCreationData[2];
cdMessage[0] = new CounterCreationData("Messages/Total", "Total
Messages Processed",
PerformanceCounterType.NumberOfItems64);
cdMessage[1] = new CounterCreationData("Messages/Second",
"Messages Processed a Second",
PerformanceCounterType.RateOfChangePerSecond32);
PerformanceCounterCategory.Create("MSDN Message Service", "MSDN
Message Service Counters", cdMessage);

  一旦定義了性能計數器類別,將創建 PerformanceCounter 對象以訪
問計數器實例功能。PerformanceCounter對象需要類別、計數器名稱和一
個可選的實例名稱。對于輔助進程,將使用來自 xml文件的進程名稱,代
碼如下:
pcMsgTotWorker = new PerformanceCounter("MSDN Message Service",
"Messages/Total", sProcessName);
pcMsgSecWorker = new PerformanceCounter("MSDN Message Service",
"Messages/Second", sProcessName);
pcMsgTotWorker.RawValue = 0;
pcMsgSecWorker.RawValue = 0;

要增加計數器的值,僅僅需要調用適當的方法:

pcMsgTotWorker.IncrementBy(1);
pcMsgSecWorker.IncrementBy(1);

最后說明一點,服務終止時,安裝的性能計數器類別應該從系統中刪除:

PerformanceCounterCategory.Delete("MSDN Message Service");

  由于性能計數器在 .NET 框架中工作,因此需要運行一項特殊的服務。
此服務(PerfCounterService)提供了共享內存。計數器信息將寫入共享
內存,并被性能計數器系統讀取。

安裝

  在結束以前,我們來簡要介紹一下安裝以及稱為 installutil.exe的
安裝工具。由于此應用程序是 Windows服務,它必須使用installutil.exe
來安裝。因此,需要使用一個從 System.Configuration.Install 程序集
中繼承的 Installer類:
public class ServiceRegister: Installer
{
  private ServiceInstaller serviceInstaller;
  private ServiceProcessInstaller processInstaller;
  public ServiceRegister()
  {
   // 創建服務安裝程序
   serviceInstaller = new ServiceInstaller();
   serviceInstaller.StartType = ServiceStart.Manual;
   serviceInstaller.ServiceName = ServiceControl.ServiceControl
   Name;
   serviceInstaller.DisplayName = ServiceControl.ServiceControl
   Desc;
   Installers.Add(serviceInstaller);
   // 創建進程安裝程序
   processInstaller = new ServiceProcessInstaller();
   processInstaller.RunUnderSystemAccount = true;
   Installers.Add(processInstaller);
  }
}

  如此示例類所示,對于一個 Windows服務,服務和服務進程各需要一
個安裝程序,以定義運行服務的帳戶。其他安裝程序允許注冊事件日志和
性能計數器等資源。

總結

  從這個 .NET 框架應用程序示例中可以看出,以前只有 Visual C++
程序員能夠編寫的應用程序,現在使用簡單的面向對象程序即可實現。盡
管我們的重點是 C# ,但本文所述的內容也同樣適用于 Visual Basic 和
Managed C++.新的 .NET 框架使開發人員能夠使用任何編程語言來創建功
能強大、可伸縮的 Windows應用程序和服務。

  新的 .NET 框架不僅簡化和擴展了編程的種種可能,還能夠輕松地將
人們經常遺忘的應用程序檢測設備(例如性能監測計數器和事件日志通知)
合并到應用程序中。盡管這里的應用程序沒有使用 Windows管理檢測設備
(WMI ),但 .NET 框架同樣也可以應用它。

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
色av中文字幕一区| 成人国产精品久久久久久亚洲| 成人激情黄色网| 亚洲第一二三四五区| 91精品在线观看视频| 2019中文字幕全在线观看| 欧美精品久久久久久久免费观看| 亚洲精品视频网上网址在线观看| 国产91|九色| 久久久久久中文| 亚洲小视频在线| 久久国产精品久久国产精品| 91免费欧美精品| 国产精品日韩久久久久| 亚洲深夜福利在线| 欧美日韩精品在线| 国内精品久久久久久久久| 国产精品久久久久9999| 国产精品色婷婷视频| 午夜精品三级视频福利| 欧美另类老肥妇| 久久久精品久久久| 亚洲一区二区在线| 国产激情999| 国产精品私拍pans大尺度在线| 日日噜噜噜夜夜爽亚洲精品| 欧洲s码亚洲m码精品一区| 国产精品极品美女在线观看免费| 亚洲mm色国产网站| 一区二区在线免费视频| 久久免费国产精品1| 日韩视频欧美视频| 在线看欧美日韩| 日韩国产精品亚洲а∨天堂免| 伊人久久久久久久久久久久久| 国产精品国内视频| 中文字幕亚洲欧美一区二区三区| 精品成人国产在线观看男人呻吟| 亚洲亚裔videos黑人hd| 国产成人综合一区二区三区| 日韩中文字幕免费视频| 91精品久久久久久| 欧美性一区二区三区| 色狠狠av一区二区三区香蕉蜜桃| 国产中文字幕日韩| 成人美女av在线直播| 国模吧一区二区| 国产精品av电影| 国产精品第一页在线| 日韩福利伦理影院免费| 91精品免费久久久久久久久| 欧美最顶级的aⅴ艳星| 奇米成人av国产一区二区三区| 久久露脸国产精品| 亚洲国产精品资源| 欧美一级淫片videoshd| 国模精品一区二区三区色天香| 欧美另类在线播放| 日韩在线免费视频观看| 久久99久久99精品免观看粉嫩| 青青久久aⅴ北条麻妃| 国产ts人妖一区二区三区| 日本乱人伦a精品| 欧美国产高跟鞋裸体秀xxxhd| 97在线看免费观看视频在线观看| 亚洲精品欧美日韩专区| 久久精品久久久久久国产 免费| 国产精品极品尤物在线观看| 日韩av中文在线| 精品丝袜一区二区三区| 97碰碰碰免费色视频| 另类专区欧美制服同性| 91精品国产综合久久香蕉922| 亚洲欧洲高清在线| 国产脚交av在线一区二区| 国产欧美久久一区二区| 欧美乱妇高清无乱码| 久久精品国产精品| 亚洲人精选亚洲人成在线| 欧洲成人免费aa| 国产www精品| 亚洲男人av电影| 国产精品久久久久免费a∨| 欧美国产一区二区三区| 欧美成年人视频网站欧美| 日韩成人中文字幕在线观看| 日韩精品视频在线观看免费| 国产精品久久久久77777| 久久影视免费观看| 色综合久久88| 亚洲少妇中文在线| 国产精品久久久久久中文字| 精品美女久久久久久免费| 亚洲一区制服诱惑| 国产精品视频yy9099| wwwwwwww亚洲| 成人日韩av在线| 国产精自产拍久久久久久蜜| 日韩电影中文字幕| 日韩亚洲一区二区| 伊人伊成久久人综合网站| 欧美日韩性视频在线| 成人午夜激情免费视频| 国产精品久久久久久网站| 成人免费直播live| 福利一区福利二区微拍刺激| 欧美激情第99页| 久久男人av资源网站| 九九精品视频在线| 欧美视频第一页| 欧美在线视频a| 久久精品2019中文字幕| 欧美中文字幕在线| 欧美激情视频一区二区| 在线视频一区二区| 欧美亚洲日本网站| 欧美成人手机在线| 在线国产精品视频| 日韩av在线播放资源| 亚洲天堂视频在线观看| 久久亚洲综合国产精品99麻豆精品福利| 午夜精品在线视频| 欧美午夜无遮挡| 国产精品一区二区三区久久| 欧美专区福利在线| 亚洲天堂男人天堂| 日韩av综合网站| 成人免费网站在线看| 免费91麻豆精品国产自产在线观看| 欧美一级淫片aaaaaaa视频| 国产精品久久久久久久电影| 一区二区三区亚洲| 国产日韩中文在线| 国产视频亚洲精品| 欧美精品一区在线播放| 51视频国产精品一区二区| 久久夜精品香蕉| 最近2019年日本中文免费字幕| 亚洲国产高潮在线观看| 欧美小视频在线| 国产精品va在线播放我和闺蜜| 欧美日韩亚洲国产一区| 色视频www在线播放国产成人| 97香蕉久久夜色精品国产| 亚洲激情视频在线观看| 91精品国产91久久久久福利| 91精品国产色综合| 亚洲欧美综合区自拍另类| 欧美日韩成人在线播放| 在线播放精品一区二区三区| 色无极影院亚洲| 精品中文字幕久久久久久| 精品国产拍在线观看| 国外成人在线播放| 色偷偷av亚洲男人的天堂| 久久久久久久91| 欧美日本精品在线| 国产精品欧美激情在线播放| 久久影院资源站| 色综合亚洲精品激情狠狠| 懂色av中文一区二区三区天美| 精品视频久久久久久| 久久久久久伊人| 国产日韩中文字幕|