Ошибка очереди сообщений: не удается найти средство форматирования, способное читать сообщения - PullRequest
27 голосов
/ 17 марта 2009

Я пишу сообщения в очередь сообщений на C # следующим образом:

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

Я пытаюсь прочитать сообщения следующим образом:

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

Однако я получаю сообщение об ошибке: «Не удается найти модуль форматирования, способный прочитать это сообщение».

Что я делаю не так?

Ответы [ 9 ]

36 голосов
/ 18 марта 2009

Я решил проблему, добавив форматер к каждому сообщению. Добавление средства форматирования в очередь не сработало.

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
}
25 голосов
/ 18 августа 2009

Или вы можете использовать

 message.Formatter =
     new System.Messaging.XmlMessageFormatter(new Type[1] { typeof(string) });
6 голосов
/ 15 февраля 2011

вы можете попробовать прочитать текст сообщения вместо тела, например:

StreamReader sr = new StreamReader(m.BodyStream);    
string messageBody = "";    
while (sr.Peek() >= 0) 
{
    messageBody += sr.ReadLine();
}
4 голосов
/ 31 августа 2013
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" });
2 голосов
/ 29 мая 2014

Все здесь проделали фантастическую работу по поиску решений, и, только что закончив борьбу с этой проблемой самостоятельно, я хотел добавить свой собственный 2c и показать решение, которое я нашел, которое работает очень хорошо.

Во-первых, когда создается очередь, я удостоверяюсь, что открываю разрешения примерно так (меня не волнует безопасность очереди в контексте нашего приложения ... это расчетное решение):

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

Без этой строки я получал бы всевозможные недоступные ошибки и даже не мог просматривать очередь с экрана управления компьютером. Кстати, если это случится с вами, и вы задаетесь вопросом, как убить очередь, к которой у вас нет доступа, просто:

  1. Остановить услугу «Очередь сообщений»
  2. Перейти к "C: \ Windows \ System32 \ msmq \ storage \ lqs"
  3. Откройте каждый файл в блокноте и найдите имя своей очереди (это, скорее всего, будет файл, который был изменен последним)
  4. Удалите этот файл и перезапустите службу обмена сообщениями

Создайте базовый класс для элементов сообщений в очереди и отметьте его [Сериализуемый]. При загрузке приложения кешируйте список всех ваших типов сообщений, используя что-то вроде этого:

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!

2 голосов
/ 20 октября 2010

Кажется, что сериализация выполняется только при доступе к свойству Body класса Message. До тех пор, пока вы обращаетесь к свойству Body после установки в сообщении правильного Formatter, оно работает нормально.

Если вы предпочитаете не создавать средство форматирования для каждого сообщения, вы можете установить средство форматирования в очереди и для каждого сообщения (до получения доступа к свойству Body) установить свойство Formatter из средства форматирования очереди.

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

var msg = _qeueu.Receive();
msg.Formatter = _queue.Formatter;
var myObject = (MyClass) msg.Body;
1 голос
/ 26 апреля 2016

Это помогло мне прочитать приватную очередь с удаленного компьютера:

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();
0 голосов
/ 30 июня 2017

Добавление форматера решило мою проблему:

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

Вы можете увидеть пример кода и библиотеку msmq на github: https://github.com/beyazc/MsmqInt

0 голосов
/ 16 апреля 2014

это работает очень хорошо:

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