2009-03-17 12 views
25

ich Nachrichten an eine Message Queue in C# zu schreiben, wie folgt:Message Queue-Fehler: kann kein Formatierer lesen kann Nachricht finden

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

Ich versuche, die Nachrichten zu lesen wie folgt:

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

Ich bekomme jedoch eine Fehlermeldung, die besagt: "Kann einen Formatierer nicht finden, der diese Nachricht lesen kann."

Was mache ich falsch?

Antwort

35

Ich löste das Problem, indem ich jeder Nachricht einen Formatierer hinzufügte. Das Hinzufügen eines Formatierungsprogramms zur Warteschlange funktionierte nicht.

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 
} 
+0

Perfekt! Genau was ich wollte. – NLV

25

Oder Sie können

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

Ich denke, das ist der akzeptierten Antwort vorzuziehen. Es ist mehr "stark" im Vergleich zur Angabe des vollständigen Typnamens als String. –

2

verwenden Es scheint, dass die Serialisierung nur erfolgt, wenn der Body-Eigenschaft der Message-Klasse zugreifen. Solange Sie auf die Body-Eigenschaft zugreifen, nachdem Sie die Nachricht richtig formatiert haben, funktioniert es einwandfrei.

Wenn Sie für jede Nachricht keinen Formatierer erstellen möchten, können Sie den Formatierer in der Warteschlange und für jede Nachricht (vor dem Zugriff auf die Eigenschaft Body) die Formatter-Eigenschaft aus dem Formatierer der Warteschlange festlegen.

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

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

Sie könnten versuchen, die bodystream der anstelle des Körpers Nachricht lesen, wie folgt aus:

StreamReader sr = new StreamReader(m.BodyStream);  
string messageBody = "";  
while (sr.Peek() >= 0) 
{ 
    messageBody += sr.ReadLine(); 
} 
+1

Die 'StreamReader'-Klasse hat eine Methode' ReadToEnd', die besser funktioniert als eine Reihe von String-Objekten zu loopen und aufzubauen. –

2
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 gesetzt Formatter werden.

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

das funktioniert sehr gut:

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

Jeder hier einen fantastischen Job bei der Bereitstellung von Lösungen getan hat, und dieses Problem gerade beendet haben, kämpfen selbst ich in meinem eigenen 2c werfen wollte und zeigen die Lösung Ich dachte, das funktioniert sehr gut.

Erstens, wenn die Warteschlange ich sicherstellen, dass ich erstellt die Berechtigungen öffnen sich wie so (ich bin über Warteschlange Sicherheit im Rahmen unserer Anwendung nicht betroffen ... dies ist eine kalkulierte Entscheidung):

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

Ohne diese Zeile würde ich alle möglichen unzugänglichen Fehler erhalten und konnte nicht einmal die Warteschlange von der Computer-Management-Bildschirm durchsuchen.Nebenbei bemerkt, wenn das passiert Ihnen und Sie sich fragen, wie die Schlange zu töten, die Sie haben keinen Zugriff auf nur:

  1. Beenden Sie den Dienst „Message Queuing“
  2. Goto „C: \ Windows \ System32 \ mSMQ \ storage \ lqs“
  3. Öffnen sie jede Datei in Notepad und suchen sie die Queue-Namen (es wird höchstwahrscheinlich die Datei sein, die zuletzt geändert wurde)
  4. diese Datei löschen und den Messaging-Dienst
neu starten

Erstellen Sie eine Basisklasse f oder Ihre Warteschlangennachrichten und markieren Sie sie [Serializable]. Auf Antrag Last-Cache eine Liste aller Nachrichtentypen so etwas wie dies mit:

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

Jetzt können Sie den Empfang von Nachrichten zu beginnen. Mein erster Instinkt war, nach Nachrichten zu suchen, aber die API mag es nicht, so zu arbeiten. Also erstelle ich einen Hintergrund-Thread und rufe die Blockierungsmethode Empfangen in der Warteschlange auf, die zurückkehrt, sobald eine Nachricht verfügbar ist. Von dort aus der Nachricht Dekodierung ist so einfach wie:

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; 

Und das sollte alles, was Sie benötigen, um gut umgesetzt, typsicher MSMQ Integration sein!

1

Das ist für mich gearbeitet, um eine private Warteschlange von einem entfernten Rechner zu lesen:

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

Hinzufügen Formatierer mein Problem gelöst:

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

Sie Beispielcode und msmq Bibliothek auf Github sehen: https://github.com/beyazc/MsmqInt

Verwandte Themen