Fila de Mensagem de erro: não é possível encontrar um formatador capaz de mensagem de leitura

StackOverflow https://stackoverflow.com/questions/655276

  •  19-08-2019
  •  | 
  •  

Pergunta

Eu estou escrevendo mensagens para uma fila de mensagens em C # da seguinte forma:

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

Eu estou tentando ler as mensagens da seguinte forma:

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

No entanto, eu estou recebendo uma mensagem de erro que diz: "Não consegue encontrar um formatador capaz de ler esta mensagem"

O que estou fazendo de errado?

Foi útil?

Solução

Eu resolvi o problema adicionando um formatador para cada mensagem. Adicionando um formatador para a fila não trabalho.

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
}

Outras dicas

Ou você pode usar

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

você pode tentar ler o BodyStream da mensagem em vez do corpo, como este:

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

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

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

fila de espera deve ser definido Formatter também.

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

Parece que a serialização é feito somente quando estiver acessando a propriedade corpo da classe Message. Contanto que você acessar a propriedade corpo depois de definir sobre a mensagem à direita Formatter ele funciona bem.

Se você não preferir criar uma Formatter para cada mensagem pode definir o formatador na fila e para cada mensagem (antes de acessar a propriedade Body) definir a propriedade Formatter do Formatter da fila.

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

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

Todo mundo aqui tem feito um trabalho fantástico em soluções que fornecem, e tendo acabado de lutar este problema me eu queria jogar meu próprio 2c e mostrar a solução que eu vim com que funciona muito bem.

Em primeiro lugar, quando a fila é criada eu me certificar de que abrir as permissões assim (eu não estou preocupado com a segurança de fila no contexto da nossa aplicação ... esta é uma decisão calculada):

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

Sem essa linha que eu iria receber todos os tipos de erros de difícil acesso e não poderia até mesmo navegar na fila da tela de gerenciamento do computador. Aliás, se isso acontecer com você e você está querendo saber como matar a fila que você não tem acesso a apenas:

  1. Parar o serviço "Message Queuing"
  2. Goto "C: \ Windows \ System32 \ msmq \ STORAGE \ LQS"
  3. Abra cada arquivo no bloco de notas e olhar para o seu nome da fila (que provavelmente será o arquivo que foi modificado mais recentemente)
  4. Excluir o arquivo e reinicie o serviço de mensagens

Criar uma classe base para seus itens Message Queue e marcá-lo [Serializable]. Em cache de carga de aplicativos uma lista de todos os tipos de mensagens usando algo parecido com isto:

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

Agora você está pronto para começar a receber mensagens. Meu primeiro instinto foi o de pesquisa para mensagens, mas a API não realmente gosto de trabalhar dessa forma. Então eu criar uma discussão de fundo e chamar o método de bloqueio de recepção na fila que irá retornar uma vez que uma mensagem está disponível. De lá decodificar a mensagem é tão simples como:

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;

E isso deve ser tudo que você precisa para começar bem implementado, typesafe integração MSMQ!

Isso funcionou para mim ler uma fila particular de uma máquina remota:

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

isso funciona muito bem:

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

Adicionando formatador resolvido o meu problema:

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

Você pode ver exemplos de código e biblioteca msmq no github: https://github.com/beyazc/MsmqInt

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top