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

StackOverflow https://stackoverflow.com/questions/655276

  •  19-08-2019
  •  | 
  •  

Pregunta

Estoy escribiendo mensajes en 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, recibo un mensaje de error que dice: "No se puede encontrar un formateador capaz de leer este mensaje".

¿Qué estoy haciendo mal?

¿Fue útil?

Solución

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
}

Otros consejos

O puedes usar

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

puede intentar leer el flujo del cuerpo del mensaje en lugar del cuerpo, de esta manera:

StreamReader sr = new StreamReader(m.BodyStream);    
string messageBody = "";    
while (sr.Peek() >= 0) 
{
    messageBody += sr.ReadLine();
}
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 estar configurada.

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

Parece que la serialización solo se realiza cuando se accede a la propiedad Body de la clase Message. Siempre que acceda a la propiedad Cuerpo después de establecer 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 Cuerpo) 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;

Todos aquí han hecho un trabajo fantástico al proporcionar soluciones, y al terminar de resolver 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 así (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 podría examinar la cola desde la pantalla de administración de la computadora. Por cierto, si eso te sucede y te preguntas cómo matar la cola a la que no tienes acceso solo:

  1. Detener el servicio " Message Queue Server "
  2. Ir a " C: \ Windows \ System32 \ msmq \ storage \ lqs "
  3. Abra cada archivo en el bloc de notas y busque el nombre de su cola (probablemente será el archivo que se modificó más recientemente)
  4. Eliminar ese archivo y reiniciar el servicio de mensajería

Cree una clase base para sus elementos de mensaje de cola y márquela [Serializable]. En la aplicación, cargue el caché una lista de todos sus 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 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 implementarse bien, integración segura de MSMQ!

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();

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();
}

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);
        }
    }

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top