【问题标题】:Message Queue Error: cannot find a formatter capable of reading message消息队列错误:找不到能够读取消息的格式化程序
【发布时间】:2010-10-13 21:45:15
【问题描述】:

我正在用 C# 将消息写入消息队列,如下所示:

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

我正在尝试阅读以下消息:

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

但是我收到一条错误消息:“找不到能够读取此消息的格式化程序。”

我做错了什么?

【问题讨论】:

  • 不要使用 Microsoft 消息队列 (MSMQ)。只是不要。它已被弃用,并且在任何有用、高性能甚至远程设计良好的方面都处于劣势。

标签: c# message-queue


【解决方案1】:

我通过向每条消息添加格式化程序解决了这个问题。向队列中添加格式化程序不起作用。

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
}

【讨论】:

    【解决方案2】:

    或者你可以使用

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

    【讨论】:

    • 我认为这比接受的答案更可取。与将完整类型名称指定为字符串相比,它更“强大”。
    【解决方案3】:

    似乎只有在访问Message 类的Body 属性时才进行序列化。只要在消息上设置正确的Formatter 后访问Body 属性,它就可以正常工作。

    如果您不想为每条消息创建Formatter,您可以在队列上设置Formatter,并为每条消息(在访问Body 属性之前)从Formatter 中设置Formatter 属性排队。

    _queue.Send(new Message() { Formatter = _queue.Formatter, Body = myData } );
    
    var msg = _qeueu.Receive();
    msg.Formatter = _queue.Formatter;
    var myObject = (MyClass) msg.Body;
    

    【讨论】:

      【解决方案4】:

      您可以尝试阅读消息的正文流而不是正文,如下所示:

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

      【讨论】:

      • StreamReader 类有一个方法 ReadToEnd,它比循环和构建一系列 string 对象的性能更好。
      【解决方案5】:
      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 也必须设置 Formatter。

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

      【讨论】:

        【解决方案6】:

        这很好用:

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

        【讨论】:

          【解决方案7】:

          这里的每个人都在提供解决方案方面做得非常出色,并且我自己刚刚解决了这个问题,我想把我自己的 2c 投入进去,并展示我想出的解决方案非常有效。

          首先,当创建队列时,我确保我像这样打开权限(我不关心我们应用程序上下文中的队列安全性......这是一个经过计算的决定):

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

          如果没有该行,我会收到各种无法访问的错误,甚至无法从计算机管理屏幕浏览队列。顺便说一句,如果这种情况发生在您身上,并且您想知道如何终止您无权访问的队列:

          1. 停止“消息队列”服务
          2. 转到“C:\Windows\System32\msmq\storage\lqs”
          3. 在记事本中打开每个文件并查找您的队列名称(很可能是最近修改的文件)
          4. 删除该文件并重新启动消息服务

          为您的队列消息项创建一个基类并将其标记为 [Serializable]。 在应用程序加载缓存所有消息类型的列表,使用如下:

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

          现在您可以开始接收消息了。我的第一直觉是轮询消息,但 api 并不喜欢那样工作。因此,我创建了一个后台线程并在队列上调用阻塞方法 Receive,一旦消息可用,该方法将返回。从那里解码消息就像这样简单:

          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;
          

          这应该是您获得良好实现、类型安全的 MSMQ 集成所需的全部内容!

          【讨论】:

          • 我不知道您为什么没有为此获得更多支持。这是通用的,很有效
          【解决方案8】:

          这对我来说可以从远程机器读取私有队列:

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

          2019 年 11 月 29 日更新

          不要使用 Microsoft 消息队列 (MSMQ)。只是不要。它已被弃用,并且在任何有用、性能甚至远程设计良好方面都处于劣势。

          【讨论】:

          【解决方案9】:

          添加格式化程序解决了我的问题:

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

          您可以在 github 上查看示例代码和 msmq 库: https://github.com/beyazc/MsmqInt

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-07-08
            • 1970-01-01
            • 2014-10-28
            • 2013-07-18
            • 1970-01-01
            • 2021-03-11
            • 2020-03-01
            • 2015-09-17
            相关资源
            最近更新 更多