2012-03-28 25 views
7

Tengo un servicio de Windows para procesar los mensajes de MSMQ. Se basa en la siguiente lógicaProcesando mensaje de MSMQ en el servicio de Windows

· Hay un temporizador en el servicio de Windows. Cada diez minutos ejecutará el método llamado "ProcessMessages".

· Dentro de este método, primero crea una lista de messageIds existentes llamando al método GetAllMessages de la cola.

· Para cada messageId, recibe el mensaje (utilizando ReceiveById) y lo almacena en un archivo

¿Hay una mejor manera de lograr el procesamiento de mensajes?

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

Nota: El siguiente código no da el resultado deseado cuando lo hice como un servicio; sin embargo, no hay ningún error en el visor de eventos (no estoy haciendo ningún registro explícito). Funcionaba bien cuando era una aplicación de consola simple. ¿Cómo corregirlo? [Ahora funciona cuando cambié la cuenta a "Usuario" como se muestra en los comentarios a continuación]

Mi requisito de actaul es procesar todos los mensajes en intervalos de tiempo fijos, digamos a las 10 AM y las 11:00 AM solamente (en cada día) ¿Cuál es el mejor enfoque para hacer esto?

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

Probablemente sea un problema de permisos. Intente usar una de las otras cuentas integradas. –

+0

@ M.Babcock Gracias ... El servicio funcionó cuando utilicé ServiceAccount.User y proporcioné mi nombre de usuario y contraseña. ¿Cuál es la cuenta sugerida aquí? – Lijo

+1

Recomendaría ** ** no utilizar una cuenta de usuario dedicada en un entorno de producción para esto. El problema probablemente esté relacionado con [este artículo de KB] (http://support.microsoft.com/kb/952569) (se trata de Vista, pero probablemente exista el mismo problema en 7 y 2008). –

Respuesta

14

Una buena alternativa al uso de un temporizador es utilizar el método MessageQueue.BeginReceive y hacer el trabajo en caso ReceiveCompleted. De esta forma, su código esperará hasta que haya un mensaje en la cola y luego procesará el mensaje de inmediato, luego verificará para el siguiente mensaje.

Un trozo corto (un ejemplo completo en el artículo de MSDN vinculado.)

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

Mi requisito es procesar todos los mensajes en intervalos de tiempo fijos, por ejemplo, a las 10 AM y las 11:00 a.m. (en cada día). ¿Cuál es el mejor enfoque para hacer esto? – Lijo

+6

Use el Programador de tareas de Windows para ejecutar una aplicación de consola. – Tommassiov

2

Por qué no suscribirse a ReceiveCompleted evento? Otra opción, si tanto el remitente como el suscriptor son proyectos .Net en los que está trabajando, use WCF over MSMQ.

+0

Mi requisito es procesar todos los mensajes en intervalos de tiempo fijos, por ejemplo, a las 10 AM y las 11:00 a.m. (en cada día). ¿Cuál es el mejor enfoque para hacer esto? – Lijo

+1

Puede ser que deba otorgar acceso a MSMQ a la cuenta de dominio anónimo – paramosh

Cuestiones relacionadas