2012-03-28 16 views
7

Mam usługę Windows do przetwarzania komunikatów MSMQ. Opiera się na następującej logice: • W usłudze Windows jest zegar. Co dziesięć minut wykona metodę o nazwie "ProcessMessages".Przetwarzanie komunikatu MSMQ w usłudze Windows

· Wewnątrz tej metody najpierw tworzy listę istniejących identyfikatorów wiadomości, wywołując metodę GetAllMessages kolejki.

· Dla każdego komunikatu, to otrzymuje wiadomość (używając ReceiveById) i zapisuje go do pliku

Czy istnieje lepszy sposób na osiągnięcie przetwarzanie wiadomość?

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

Uwaga: Poniższy kod nie daje pożądanego rezultatu, gdy udało mi się jako usługa; jednak nie ma błędu w przeglądarce zdarzeń (nie robię żadnego jawnego rejestrowania). To działało dobrze, gdy była to prosta aplikacja konsolowa. Jak to poprawić? [Teraz działa, kiedy zmieniłem akonto na "Użytkownik", jak opisano w komentarzach poniżej]

Moim obowiązkiem aktuarnym jest przetwarzanie wszystkich wiadomości w określonych godzinach - powiedzmy o 10 rano i 11:00 (każdego dnia). Jakie jest najlepsze podejście do tego?

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

To prawdopodobnie problem z uprawnieniami. Spróbuj użyć jednego z innych wbudowanych kont. –

+0

@ M.Babcock Dzięki .. Usługa działała, gdy użyłem ServiceAccount.User i podałem moją nazwę użytkownika i hasło. Jakie jest sugerowane konto tutaj? – Lijo

+1

Gorąco polecam ** nie ** przy użyciu dedykowanego konta użytkownika w środowisku produkcyjnym. Problem jest prawdopodobnie związany z [tym artykułem KB] (http://support.microsoft.com/kb/952569) (chodzi o Vista, ale ten sam problem prawdopodobnie wystąpiłby w 7 i 2008 roku). –

Odpowiedz

14

miłą alternatywą do korzystania z samowyzwalacza jest użycie metody MessageQueue.BeginReceive i wykonać pracę w przypadku ReceiveCompleted. W ten sposób Twój kod będzie czekał, aż pojawi się komunikat w kolejce, a następnie natychmiast przetworzy komunikat, a następnie sprawdź, czy nie ma następnej wiadomości.

Krótki stub (kompletny przykład w połączonej artykuł 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

Moim żądaniem jest przetwarzanie wszystkich wiadomości w ustalonym przedziale czasu - powiedzmy o 10 rano i 11:00 (każdego dnia). Jakie jest najlepsze podejście do tego? – Lijo

+6

Użyj Harmonogramu zadań systemu Windows, aby uruchomić aplikację konsoli. – Tommassiov

2

Dlaczego nie subskrybować ReceiveCompleted wydarzenia? Inną opcją, jeśli nadawca i subskrybent to projekty .Net, nad którymi pracujesz, użyj WCF over MSMQ.

+0

Moim wymaganiem jest przetwarzanie wszystkich wiadomości w ustalonym przedziale czasowym - powiedzmy o 10 rano i 11:00 (każdego dnia). Jakie jest najlepsze podejście do tego? – Lijo

+1

Być może należy przyznać dostęp do MSMQ do anonimowego konta domeny – paramosh