Errore coda messaggi: impossibile trovare un formattatore in grado di leggere il messaggio

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

  •  19-08-2019
  •  | 
  •  

Domanda

Sto scrivendo messaggi in una coda di messaggi in C # come segue:

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

Sto cercando di leggere i messaggi come segue:

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

Comunque ricevo un messaggio di errore che dice: " Impossibile trovare un formattatore in grado di leggere questo messaggio. "

Cosa sto sbagliando?

È stato utile?

Soluzione

Ho risolto il problema aggiungendo un formattatore a ciascun messaggio. L'aggiunta di un formattatore alla coda non ha funzionato.

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
}

Altri suggerimenti

Oppure puoi usare

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

potresti provare a leggere il corpo del messaggio anziché il corpo, in questo modo:

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

Anche la coda deve essere impostata su Formatter.

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

Sembra che la serializzazione venga eseguita solo quando si accede alla proprietà Body della classe Message. Finché accedi alla proprietà Body dopo aver impostato sul messaggio il giusto Formatter funziona correttamente.

Se si preferisce non creare un Formatter per ciascun messaggio, è possibile impostare il Formatter sulla coda e per ogni messaggio (prima di accedere alla proprietà Body) impostare la proprietà Formatter dal Formatter della coda.

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

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

Tutti qui hanno fatto un lavoro fantastico nel fornire soluzioni, e avendo appena finito di combattere questo problema da solo, volevo inserire il mio 2c e mostrare la soluzione che mi è venuta in mente che funziona molto bene.

In primo luogo quando viene creata la coda, mi assicuro di aprire le autorizzazioni in questo modo (non sono preoccupato per la sicurezza della coda nel contesto della nostra applicazione ... questa è una decisione calcolata):

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

Senza quella linea riceverei ogni sorta di errori inaccessibili e non potrei nemmeno sfogliare la coda dalla schermata di gestione del computer. Per inciso se questo ti accade e ti stai chiedendo come uccidere la coda a cui non hai accesso solo:

  1. Interrompi il servizio " Accodamento messaggi "
  2. Vai a & C; \ C: \ Windows \ System32 \ msmq \ storage \ lqs "
  3. Apri ogni file nel blocco note e cerca il nome della tua coda (molto probabilmente sarà il file che è stato modificato più di recente)
  4. Elimina quel file e riavvia il servizio di messaggistica

Crea una classe base per gli elementi del messaggio in coda e contrassegnala [Serializable]. Nella cache di caricamento delle applicazioni un elenco di tutti i tipi di messaggi che utilizzano qualcosa del genere:

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

Ora sei pronto per iniziare a ricevere messaggi. Il mio primo istinto è stato quello di sondare i messaggi, ma all'API non piace molto lavorare così. Quindi creo un thread in background e chiamo il metodo di blocco Ricevi sulla coda che tornerà quando sarà disponibile un messaggio. Da lì la decodifica del messaggio è semplice come:

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 questo dovrebbe essere tutto ciò di cui hai bisogno per ottenere un'integrazione MSMQ ben funzionante e tipica!

Questo ha funzionato per me leggere una coda privata da un computer remoto:

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

funziona molto bene:

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

L'aggiunta di formatter ha risolto il mio 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);
        }
    }

Puoi vedere il codice di esempio e la libreria msmq su github: https://github.com/beyazc/MsmqInt

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top