2012-03-28 145 views
7

我有用於處理MSMQ消息的Windows服務。它依賴於以下邏輯在Windows服務中處理MSMQ消息

·在Windows服務中有一個計時器。每十分鐘它將執行名爲「ProcessMessages」的方法。

·在此方法中,它首先通過調用隊列的GetAllMessages方法來創建現有messageIds的列表。

·對於每個MESSAGEID,它接收到該消息(使用ReceiveById),並將其存儲到一個文件

是否有更好的方法來實現的消息處理?

參考:http://www.switchonthecode.com/tutorials/creating-a-simple-windows-service-in-csharp

注意:下面的代碼不會得到所需的結果時,我其作爲服務;但事件查看器中沒有錯誤(我沒有做任何明確的日誌記錄)。當它是一個簡單的控制檯應用程序時它工作正常。如何糾正? [現在它正在工作,當我改變accoun到「用戶」作爲shwon在下面的評論]

我的行爲要求是處理所有消息在固定的時間槽 - 例如在上午10點和上午11點(每天)。什麼是最好的方法來做到這一點?

namespace ConsoleSwitchApp 
{ 
    class Program : ServiceBase 
    { 
     private static Timer scheduleTimer = null; 
     static MessageQueue helpRequestQueue = null; 
     static System.Messaging.XmlMessageFormatter stringFormatter = null; 

     static void Main(string[] args) 
     { 
      ServiceBase.Run(new Program()); 
     } 

     public Program() 
     { 
      this.ServiceName = "LijosService6"; 

      //Queue initialize 
      helpRequestQueue = new MessageQueue(@".\Private$\MyPrivateQueue", false); 
      stringFormatter = new System.Messaging.XmlMessageFormatter(new string[] { "System.String" }); 

      //Set Message Filters 
      MessagePropertyFilter filter = new MessagePropertyFilter(); 
      filter.ClearAll(); 
      filter.Body = true; 
      filter.Label = true; 
      filter.Priority = true; 
      filter.Id = true; 
      helpRequestQueue.MessageReadPropertyFilter = filter; 

      //Start a timer 
      scheduleTimer = new Timer(); 
      scheduleTimer.Enabled = true; 
      scheduleTimer.Interval = 120000;//2 mins 
      scheduleTimer.AutoReset = true; 
      scheduleTimer.Start(); 
      scheduleTimer.Elapsed += new ElapsedEventHandler(scheduleTimer_Elapsed); 
     } 

     protected static void scheduleTimer_Elapsed(object sender, ElapsedEventArgs e) 
     { 
      ProcessMessages(); 
     } 

     private static void ProcessMessages() 
     { 
      string messageString = "1"; 

      //Message Processing 
      List<string> messageIdList = GetAllMessageId(); 
      foreach (string messageId in messageIdList) 
      { 
       System.Messaging.Message messages = helpRequestQueue.ReceiveById(messageId); 
       //Store the message into database 

       messages.Formatter = stringFormatter; 
       string messageBody = System.Convert.ToString(messages.Body); 

       if (String.IsNullOrEmpty(messageString)) 
       { 
        messageString = messageBody; 
       } 
       else 
       { 
        messageString = messageString + "___________" + messageBody; 
       } 
      } 

      //Write File 
      string lines = DateTime.Now.ToString(); 
      lines = lines.Replace("/", "-"); 
      lines = lines.Replace(":", "_"); 
      System.IO.StreamWriter file = new System.IO.StreamWriter("c:\\test" + lines + ".txt"); 
      file.WriteLine(messageString); 
      file.Close(); 
     } 

     private static List<string> GetAllMessageId() 
     { 
      List<string> messageIdList = new List<string>(); 

      DataTable messageTable = new DataTable(); 
      messageTable.Columns.Add("Label"); 
      messageTable.Columns.Add("Body"); 

      //Get All Messages 
      System.Messaging.Message[] messages = helpRequestQueue.GetAllMessages(); 
      for (int index = 0; index < messages.Length; index++) 
      { 
       string messageId = (System.Convert.ToString(messages[index].Id)); 
       messageIdList.Add(messageId); 

       messages[index].Formatter = stringFormatter; 
       messageTable.Rows.Add(new string[] { messages[index].Label, messages[index].Body.ToString() }); 
      } 

      return messageIdList; 
     } 


     protected override void OnStart(string[] args) 
     { 
      base.OnStart(args); 
     } 

     protected override void OnStop() 
     { 
      base.OnStop(); 
     } 
    } 
} 

namespace ConsoleSwitchApp 
{ 
    [RunInstaller(true)] 
    public class MyWindowsServiceInstaller : Installer 
    { 
     public MyWindowsServiceInstaller() 
     { 
      var processInstaller = new ServiceProcessInstaller(); 
      var serviceInstaller = new ServiceInstaller(); 

      //set the privileges 
      processInstaller.Account = ServiceAccount.LocalSystem; 
      serviceInstaller.DisplayName = "LijosService6"; 
      serviceInstaller.StartType = ServiceStartMode.Manual; 

      //must be the same as what was set in Program's constructor 

      serviceInstaller.ServiceName = "LijosService6"; 

      this.Installers.Add(processInstaller); 
      this.Installers.Add(serviceInstaller); 
     } 
    } 
} 
+1

這可能是一個權限問題。嘗試使用其他內置帳戶之一。 – 2012-03-28 16:30:59

+0

@ M.Babcock謝謝..服務工作時,我使用ServiceAccount.User並給了我的用戶名和密碼。這裏建議的帳戶是什麼? – Lijo 2012-03-30 13:13:57

+1

我強烈建議**不要**在生產環境中使用專用用戶帳戶。該問題可能與[本知識庫文章](http://support.microsoft.com/kb/952569)(這是關於Vista,但同樣的問題可能存在於7和2008年)相關。 – 2012-03-30 13:19:38

回答

14

一個不錯的選擇,使用計時器是使用MessageQueue.BeginReceive方法,並在ReceiveCompleted事件做的工作。這樣你的代碼就會等待,直到隊列中有消息,然後立即處理消息,然後檢查下一條消息。

一個短杆(鏈接的MSDN文章中一個完整的例子。)

private void Start() 
{ 
    MessageQueue myQueue = new MessageQueue(".\\myQueue"); 

    myQueue.ReceiveCompleted += 
     new ReceiveCompletedEventHandler(MyReceiveCompleted); 

    myQueue.BeginReceive(); 
} 

private static void MyReceiveCompleted(Object source, 
    ReceiveCompletedEventArgs asyncResult) 
{ 
    try 
    { 
     MessageQueue mq = (MessageQueue)source; 
     Message m = mq.EndReceive(asyncResult.AsyncResult); 

     // TODO: Process the m message here 

     // Restart the asynchronous receive operation. 
     mq.BeginReceive(); 
    } 
    catch(MessageQueueException) 
    { 
     // Handle sources of MessageQueueException. 
    } 

    return; 
} 
+0

我的要求是在固定的時間段處理所有消息 - 例如僅在上午10點和上午11點(每天)。什麼是最好的方法來做到這一點? – Lijo 2012-05-14 09:06:11

+6

使用Windows任務計劃程序運行控制檯應用程序。 – Tommassiov 2014-01-06 15:28:02

2

爲什麼不訂閱ReceiveCompleted事件?另一種選擇是,如果發件人和訂閱者都是您正在處理的.Net項目,則使用WCF over MSMQ

+0

我的要求是在固定的時間段處理所有消息 - 例如僅在上午10點和上午11點(每天)。什麼是最好的方法來做到這一點? – Lijo 2012-03-30 13:15:00

+1

可能是你應該授予訪問MSMQ匿名域帳戶 – paramosh 2012-03-30 13:43:39