2009-03-17 6 views
25

estoy escribiendo mensajes a una cola de mensajes en C# como sigue:Message Queue Error: No se puede encontrar un formateador capaz de lectura de mensajes

queue.Send(new Message("message")); 

Estoy tratando de leer los mensajes de la siguiente manera:

Messages messages = queue.GetAllMessages(); 
foreach(Message m in messages) 
{ 
    String message = m.Body; 
    //do something with string 
} 

Sin embargo recibo un mensaje de error que dice: "No se puede encontrar un formateador capaz de leer este mensaje".

¿Qué estoy haciendo mal?

Respuesta

35

Resolví el problema agregando un formateador a cada mensaje. Agregar un formateador a la cola no funcionó.

Messages messages = queue.GetAllMessages(); 
foreach(Message m in messages) 
{ 
    m.Formatter = new XmlMessageFormatter(new String[] { "System.String,mscorlib" }); 
    String message = m.Body; 

    //do something with string 
} 
+0

¡Perfecto! Justo lo que quería. – NLV

25

O puede utilizar

message.Formatter = 
    new System.Messaging.XmlMessageFormatter(new Type[1] { typeof(string) }); 
+2

Creo que esto es preferible a la respuesta aceptada. Es más "fuerte" en comparación con especificar el nombre de tipo completo como una cadena. –

2

Parece que la serialización se realiza sólo cuando se accede a la propiedad Cuerpo de la clase de mensaje. Siempre que acceda a la propiedad del cuerpo después de configurar el mensaje, el formateador correcto funciona bien.

Si prefiere no crear un formateador para cada mensaje, puede configurar el formateador en la cola y para cada mensaje (antes de acceder a la propiedad del cuerpo) establezca la propiedad del formateador desde el formateador de la cola.

_queue.Send(new Message() { Formatter = _queue.Formatter, Body = myData }); 

var msg = _qeueu.Receive(); 
msg.Formatter = _queue.Formatter; 
var myObject = (MyClass) msg.Body; 
5

podría intentar leer el bodystream del mensaje en lugar del cuerpo, como esto:

StreamReader sr = new StreamReader(m.BodyStream);  
string messageBody = "";  
while (sr.Peek() >= 0) 
{ 
    messageBody += sr.ReadLine(); 
} 
+1

La clase 'StreamReader' tiene un método' ReadToEnd' que tendrá un mejor rendimiento que el bucle y la creación de una serie de objetos 'string'. –

2
Message recoverableMessage = new Message(); 
recoverableMessage.Body = "Sample Recoverable Message"; 

recoverableMessage.Formatter = new XmlMessageFormatter(new String[] {"System.String,mscorlib" }); 

MessageQueue myQueue = new MessageQueue(@".\private$\teste"); 

cola debe ajustarse formateador también.

myQueue.Formatter = new XmlMessageFormatter(new String[] { "System.String,mscorlib" }); 
0

esto funciona muy bien:

static readonly XmlMessageFormatter f = new XmlMessageFormatter(new Type[] { typeof(String) }); 

private void Client() 
{ 
    var messageQueue = new MessageQueue(@".\Private$\SomeTestName"); 

    foreach (Message message in messageQueue.GetAllMessages()) 
    { 
     message.Formatter = f; 
     Console.WriteLine(message.Body); 
    } 
    messageQueue.Purge(); 
} 
2

Aquí todo el mundo ha hecho un trabajo fantástico en aportar soluciones, y que acaba de terminar luchando contra este problema a mí mismo que quería tirar mi propia 2c y mostrar la solución Se me ocurrió que funciona muy bien.

En primer lugar cuando se crea la cola me aseguro de abrir los permisos como tal (no estoy preocupado por la seguridad de la cola en el contexto de nuestra aplicación ... Esta es una decisión calculada):

queue.SetPermissions("Everyone", MessageQueueAccessRights.FullControl, AccessControlEntryType.Set); 

Sin esa línea recibiría todo tipo de errores inaccesibles y ni siquiera podría navegar por la cola desde la pantalla de administración de la computadora.Por cierto, si eso sucede a usted y usted se pregunta cómo matar a la cola que no tiene acceso a solo:

  1. Detener el servicio "Message Queuing"
  2. Goto "C: \ Windows \ System32 \ MSMQ \ Storage \ lqs"
  3. Abrir cada archivo en el bloc de notas y busque el nombre de la cola (lo más probable será el archivo que se ha modificado más recientemente)
  4. Eliminar el archivo y reinicie el servicio de mensajería

Crear una clase base f o sus elementos de mensaje de cola y márquelo [Serializable]. En caché carga de la aplicación de una lista de todos los tipos de mensajes que utilizan algo como esto:

var types = typeof(QueueItemBase).Assembly 
      .GetTypes() 
      .Where(t => typeof(QueueItemBase).IsAssignableFrom(t) && t.IsAbstract == false) 
      .ToArray(); 
... 
// Create and cache a message formatter instance 
_messageFormatter = new XmlMessageFormatter(types); 

Ahora ya está listo para empezar a recibir mensajes. Mi primer instinto fue buscar mensajes, pero a la API realmente no le gusta trabajar de esa manera. Así que creo un hilo de fondo y llamo al método de bloqueo Recibir en la cola que volverá una vez que haya un mensaje disponible. A partir de ahí decodificar el mensaje es tan simple como:

var message = queue.Receive(); 
if (message == null) 
    continue; 

// Tell the message about our formatter containing all our message types before we 
// try and deserialise 
message.Formatter = _messageFormatter; 

var item = message.Body as QueueItemBase; 

Y eso debería ser todo lo que necesita para bien implementado, typesafe integración MSMQ!

1

Esto funcionó para mí para leer una cola privada desde una máquina remota:

MessageQueue queue = new MessageQueue(@"FormatName:Direct=OS:MACHINENAME\private$\MyQueueName", QueueAccessMode.Peek); 

Message msg = queue.Peek(); 
StreamReader sr = new StreamReader(msg.BodyStream); 
string messageBody = sr.ReadToEnd(); 
0

Adición de formateador resuelto mi problema:

public void ReceiveAsync<T>(MqReceived<T> mqReceived) 
    { 
     try 
     { 
      receiveEventHandler = (source, args) => 
      { 
       var queue = (MessageQueue)source; 
       using (Message msg = queue.EndPeek(args.AsyncResult)) 
       { 
        XmlMessageFormatter formatter = new XmlMessageFormatter(new Type[] { typeof(T) }); 
        msg.Formatter = formatter; 
        queue.ReceiveById(msg.Id); 
        T tMsg = (T)msg.Body; 
        mqReceived(tMsg); 

       } 
       queue.BeginPeek(); 
      }; 

      messageQueu.PeekCompleted += receiveEventHandler; 
      messageQueu.BeginPeek(); 

     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.Message); 
     } 
    } 

Se puede ver ejemplos de código y la biblioteca msmq en github: https://github.com/beyazc/MsmqInt

Cuestiones relacionadas