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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/655276/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 12:04:24  来源:igfitidea点击:

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

c#message-queue

提问by macleojw

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

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

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

I'm trying to read the messages as follows:

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

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

However I'm getting an error message which says: "Cannot find a formatter capable of reading this message."

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

What am I doing wrong?

我究竟做错了什么?

采纳答案by macleojw

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
}

回答by prime23

Or you can use

或者你可以使用

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

回答by selalerer

It seems that the serialization is only done when accessing the Bodyproperty of the Messageclass. As long as you access the Bodyproperty after you set on the message the right Formatterit works fine.

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

If you prefer not to create a Formatterfor each message you can set the Formatteron the queue and for each message (before accessing the Body property) set the Formatterproperty from the Formatterof the queue.

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

_queue.Send(new Message() { Formatter = _queue.Formatter, Body = myData } );

var msg = _qeueu.Receive();
msg.Formatter = _queue.Formatter;
var myObject = (MyClass) msg.Body;

回答by felbus

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

回答by Mr Milk

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

回答by harveyt

this works very fine:

这工作得很好:

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

回答by Paul Carroll

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.

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

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

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:

为您的队列消息项创建一个基类并将其标记为 [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);

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:

现在您已准备好开始接收消息。我的第一直觉是轮询消息,但 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;

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

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

回答by Contango

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

更新 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.

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

回答by cahit beyaz

Adding formatter solved my issue:

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

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

You can see sample code and msmq library on github: https://github.com/beyazc/MsmqInt

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