Message Queue Error: cannot find a formatter capable of reading message

前端 未结 9 1767
耶瑟儿~
耶瑟儿~ 2020-12-15 16:24

I\'m writing messages to a Message Queue in C# as follows:

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

I\'m trying to read the messages as follow

相关标签:
9条回答
  • 2020-12-15 17:00

    you could try reading the bodystream of the message instead of the body, like this:

    StreamReader sr = new StreamReader(m.BodyStream);    
    string messageBody = "";    
    while (sr.Peek() >= 0) 
    {
        messageBody += sr.ReadLine();
    }
    
    0 讨论(0)
  • 2020-12-15 17:08

    I solved the problem by adding a formatter to each message. Adding a formatter to the queue didn't work.

    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 讨论(0)
  • 2020-12-15 17:09

    This worked for me to read a private queue from a remote machine:

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

    Update 2019-11-29

    Don't use Microsoft Message Queue (MSMQ). Just don't. It is both deprecated, and bottom of the pile in terms of anything useful, performant or even remotely well designed.

    0 讨论(0)
  • 2020-12-15 17:11
    Message recoverableMessage = new Message();
    recoverableMessage.Body = "Sample Recoverable Message";
    
    recoverableMessage.Formatter = new XmlMessageFormatter(new String[] {"System.String,mscorlib" });
    
    MessageQueue myQueue = new MessageQueue(@".\private$\teste");
    

    Queue must be set Formatter too.

    myQueue.Formatter = new XmlMessageFormatter(new String[] { "System.String,mscorlib" });
    
    0 讨论(0)
  • 2020-12-15 17:16

    Everyone here has done a fantastic job at providing solutions, and having just finished battling this problem myself I wanted to throw my own 2c in and show the solution I came up with that works very well.

    Firstly when the queue is created I make sure I open up the permissions like so (I'm not concerned about queue security in the context of our application... this is a calculated decision):

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

    Without that line I would receive all sorts of inaccessible errors and couldn't even browse the queue from the computer management screen. Incidentally if that happens to you and you're wondering how to kill the queue that you don't have access to just:

    1. Stop the service "Message Queueing"
    2. Goto "C:\Windows\System32\msmq\storage\lqs"
    3. Open each file in notepad and look for your queue name (it will most likely be the file that was most recently modified)
    4. Delete that file and restart the Messaging service

    Create a base class for your queue message items and mark it [Serializable]. On application load cache a list of all your message types using something like this:

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

    Now you're ready to start receiving messages. My first instinct was to poll for messages, but the api doesn't really like working that way. So I create a background thread and call the blocking method Receive on the queue which will return once a message is available. From there decoding the message is as simple as:

    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;
    

    And that should be all you need to get nicely implemented, typesafe MSMQ integration!

    0 讨论(0)
  • 2020-12-15 17:19

    It seems that the serialization is only done when accessing the Body property of the Message class. As long as you access the Body property after you set on the message the right Formatter it works fine.

    If you prefer not to create a Formatter for each message you can set the Formatter on the queue and for each message (before accessing the Body property) set the Formatter property from the Formatter of the queue.

    _queue.Send(new Message() { Formatter = _queue.Formatter, Body = myData } );
    
    var msg = _qeueu.Receive();
    msg.Formatter = _queue.Formatter;
    var myObject = (MyClass) msg.Body;
    
    0 讨论(0)
提交回复
热议问题