28

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

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

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

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

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

我究竟做错了什么?

4

9 回答 9

37

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

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
}
于 2009-03-18T10:25:58.907 回答
25

或者你可以使用

 message.Formatter =
     new System.Messaging.XmlMessageFormatter(new Type[1] { typeof(string) });
于 2009-08-18T02:00:33.807 回答
6

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

StreamReader sr = new StreamReader(m.BodyStream);    
string messageBody = "";    
while (sr.Peek() >= 0) 
{
    messageBody += sr.ReadLine();
}
于 2011-02-15T13:35:25.563 回答
4
Message recoverableMessage = new Message();
recoverableMessage.Body = "Sample Recoverable Message";

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

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

队列也必须设置格式化程序。

myQueue.Formatter = new XmlMessageFormatter(new String[] { "System.String,mscorlib" });
于 2013-08-30T20:06:15.440 回答
3

这里的每个人都在提供解决方案方面做得非常出色,并且我自己刚刚完成了与这个问题的斗争,我想投入我自己的 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 集成所需的全部内容!

于 2014-05-28T23:28:18.283 回答
2

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

如果您不想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;
于 2010-10-20T15:28:25.030 回答
2

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

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)。只是不要。就任何有用的、高性能的甚至远程精心设计的东西而言,它都已被弃用,而且是最底层的。

于 2016-04-26T15:11:05.347 回答
0

这很好用:

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();
}
于 2014-04-15T20:17:38.617 回答
0

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

 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

于 2017-06-30T07:50:16.097 回答