消息队列错误:找不到能够读取消息的格式化程序

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

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

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

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

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

我究竟做错了什么?

我通过在每条消息中添加格式化程序来解决问题。 将格式化程序添加到队列不起作用。

 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 } 

或者你可以使用

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

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

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

似乎只有在访问Message类的Body属性时才会进行序列化。 只要您在消息上设置正确的格式化程序后访问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; 

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

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

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

如果没有该行,我将收到各种无法访问的错误,甚至无法从计算机管理屏幕浏览队列。 顺便说一句,如果你遇到这种情况,并且想知道如何杀死你无权访问的队列:

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

为队列消息项创建基类并将其标记为[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集成!

 Message recoverableMessage = new Message(); recoverableMessage.Body = "Sample Recoverable Message"; recoverableMessage.Formatter = new XmlMessageFormatter(new String[] {"System.String,mscorlib" }); MessageQueue myQueue = new MessageQueue(@".\private$\teste"); 

队列也必须设置为Formatter。

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

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

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

这很好用:

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

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

  public void ReceiveAsync(MqReceived 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