Error en la cola de mensajes: no se puede encontrar un formateador capaz de leer mensajes


Estoy escribiendo mensajes a una Cola de mensajes en C# de la siguiente manera:

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, estoy recibiendo un mensaje de error que dice: "No puedo encontrar un formateador capaz de leer este mensaje."

¿Qué estoy haciendo mal?

Author: Mr Lister, 2009-03-17

9 answers

Resolví el problema añadiendo 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
}
 36
Author: macleojw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-09 02:29:46

O puede usar

 message.Formatter =
     new System.Messaging.XmlMessageFormatter(new Type[1] { typeof(string) });
 25
Author: prime23,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-18 02:00:33

Podrías intentar leer el bodystream del mensaje en lugar del cuerpo, así:

StreamReader sr = new StreamReader(m.BodyStream);    
string messageBody = "";    
while (sr.Peek() >= 0) 
{
    messageBody += sr.ReadLine();
}
 5
Author: felbus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-25 20:10:11

Parece que la serialización solo se realiza cuando se accede a la propiedad Body de la clase Message. Siempre y cuando acceda a la propiedad Body después de configurar en el mensaje el formateador correcto, funciona bien.

Si prefiere no crear un Formateador para cada mensaje, puede establecer el Formateador en la cola y para cada mensaje (antes de acceder a la propiedad Body) establecer la propiedad 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;
 2
Author: selalerer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-20 15:28:25
Message recoverableMessage = new Message();
recoverableMessage.Body = "Sample Recoverable Message";

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

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

La cola también debe configurarse Formateador.

myQueue.Formatter = new XmlMessageFormatter(new String[] { "System.String,mscorlib" });
 2
Author: Mr Milk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-30 20:33:02

Todos aquí han hecho un trabajo fantástico en proporcionar soluciones, y después de haber terminado de luchar contra este problema yo mismo quería lanzar mi propio 2c y mostrar la solución que se me ocurrió que funciona muy bien.

En primer lugar, cuando se crea la cola me aseguro de abrir los permisos de esta manera (no me preocupa 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 podía navegar por la cola desde la pantalla de administración del equipo. Por cierto, si eso te sucede y te estás preguntando cómo matar la cola a la que no tienes acceso solo:

  1. Detener el servicio "Message Queue"
  2. Goto "C:\Windows\System32\msmq\storage\lqs"
  3. Abra cada archivo en el bloc de notas y busque el nombre de la cola (lo más probable es que sea el archivo que se modificó más recientemente)
  4. Elimine ese archivo y reinicie el mensaje servicio

Cree una clase base para los elementos de mensaje de la cola y márquela [Serializable]. On application load cache una lista de todos los tipos de mensajes usando 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 está listo para comenzar a recibir mensajes. Mi primer instinto fue sondear mensajes, pero a la api no le gusta trabajar de esa manera. Así que creo un hilo en segundo plano y llamo al método de bloqueo Receive en la cola que volverá una vez que el mensaje esté disponible. Desde allí decodificación 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 implementarse bien, ¡integración typesafe MSMQ!

 2
Author: Paul Carroll,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-28 23:28:18

Esto me funcionó 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();
 1
Author: Contango,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-26 15:11:05

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();
}
 0
Author: harveyt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-15 20:17:38

Agregar formateador resolvió 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);
        }
    }

Puedes ver el código de ejemplo y la biblioteca msmq en github: https://github.com/beyazc/MsmqInt

 0
Author: cahit beyaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-30 07:50:16