2012-03-28 2 views
7

J'ai un service Windows pour le traitement des messages MSMQ. Il repose sur la logique suivanteTraitement du message MSMQ dans le service Windows

· Il existe un temporisateur dans le service Windows. Toutes les dix minutes, il exécutera la méthode nommée "ProcessMessages".

· À l'intérieur de cette méthode, il crée d'abord une liste de messages existants en appelant la méthode GetAllMessages de la file d'attente.

· Pour chaque messageId, il reçoit le message (en utilisant ReceiveById) et le stocke dans un fichier

Y at-il une meilleure façon d'obtenir le traitement des messages?

Référence: http://www.switchonthecode.com/tutorials/creating-a-simple-windows-service-in-csharp

Note: Le code suivant ne donne pas le résultat souhaité lorsque je l'ai fait en tant que service; Cependant, il n'y a pas d'erreur dans la visionneuse d'événements (je ne fais aucune journalisation explicite). Cela fonctionnait bien quand c'était une application de console simple. Comment le corriger? [Maintenant, ça marche quand j'ai changé le nom "Utilisateur" comme shwon dans les commentaires ci-dessous]

Mon besoin actaul est de traiter tous les messages à des intervalles de temps fixes - disons à 10 h et 11 h seulement (chaque jour). Quelle est la meilleure approche pour le faire?

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

C'est probablement un problème d'autorisations. Essayez d'utiliser l'un des autres comptes intégrés. –

+0

@ M.Babcock Merci .. Service travaillé quand j'ai utilisé ServiceAccount.User et donné mon nom d'utilisateur et mot de passe. Quel est le compte suggéré ici? – Lijo

+1

Je recommande fortement de ne pas ** utiliser ** un compte d'utilisateur dédié dans un environnement de production pour cela. Le problème est probablement lié à [cet article de la base de connaissances] (http://support.microsoft.com/kb/952569) (il s'agit de Vista mais le même problème existerait probablement en 7 et 2008). –

Répondre

14

Une belle alternative à l'utilisation d'une minuterie est d'utiliser la méthode MessageQueue.BeginReceive et faire du travail en cas ReceiveCompleted. De cette façon, votre code attendra jusqu'à ce qu'il y ait un message dans la file d'attente, puis traite immédiatement le message, puis vérifie le message suivant.

Un talon court (un exemple complet dans l'article MSDN lié.)

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

Mon exigence est de traiter tous les messages à intervalles de temps fixes - disons à 10h et 11h seulement (chaque jour). Quelle est la meilleure approche pour le faire? – Lijo

+6

Utilisez le planificateur de tâches Windows pour exécuter une application de console. – Tommassiov

2

Pourquoi ne pas souscrire à l'événement ReceiveCompleted? Une autre option, si l'expéditeur et l'abonné sont des projets .Net sur lesquels vous travaillez, utilisez WCF over MSMQ.

+0

Mon exigence est de traiter tous les messages à intervalles de temps fixes - disons à 10h et 11h seulement (chaque jour). Quelle est la meilleure approche pour le faire? – Lijo

+1

Peut-être que vous devriez accorder l'accès à MSMQ au compte de domaine anonyme – paramosh

Questions connexes