2009-03-17 6 views
25

J'écris des messages à une file d'attente du message en C# comme suit:Message d'erreur de file d'attente: ne peut pas trouver un formatter capable de lire un message

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

Je suis en train de lire les messages comme suit:

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

Cependant, je reçois un message d'erreur qui dit: "Impossible de trouver un formateur capable de lire ce message."

Qu'est-ce que je fais mal?

Répondre

35

J'ai résolu le problème en ajoutant un formateur à chaque message. L'ajout d'un formateur à la file d'attente n'a pas fonctionné.

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

Parfait! Juste ce que je voulais. – NLV

25

Ou vous pouvez utiliser

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

Je pense que c'est préférable à la réponse acceptée. Il est plus "fort" comparé à la spécification du nom de type complet en tant que chaîne. –

2

Il semble que la sérialisation ne se fait lors de l'accès à la propriété du corps de la classe de message. Tant que vous accédez à la propriété Body après avoir défini le bon Formatter sur le message, cela fonctionne correctement. Si vous préférez ne pas créer de formateur pour chaque message, vous pouvez définir le formateur dans la file d'attente et pour chaque message (avant d'accéder à la propriété Body), définissez la propriété Formatter à partir du formateur de la file d'attente.

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

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

vous pouvez essayer de lire le bodystream du message au lieu du corps, comme celui-ci:

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

La classe 'StreamReader' a une méthode' ReadToEnd' qui fonctionnera mieux que de boucler et de construire une série d'objets 'string'. –

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

File d'attente doit être Formatter aussi.

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

cela fonctionne très bien:

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

Tout le monde ici a fait un travail fantastique à fournir des solutions, et juste après avoir fini moi-même aux prises avec ce problème, je voulais jeter mon propre 2c et montrer la solution Je suis arrivé avec ça fonctionne très bien.

Tout d'abord lorsque la file d'attente est créée, je fais que j'ouvrir les autorisations comme si (je ne suis pas préoccupé par la sécurité de file d'attente dans le contexte de notre application ... ceci est une décision calculée):

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

Sans cette ligne, je recevrais toutes sortes d'erreurs inaccessibles et ne pouvais même pas parcourir la file d'attente à partir de l'écran de gestion de l'ordinateur.Soit dit en passant, si cela vous arrive et vous vous demandez comment tuer la file d'attente que vous n'avez pas accès à tout:

  1. Arrêtez le service « Message Queuing »
  2. Aller à « C: \ Windows \ System32 \ MSMQ \ storage \ lqs »
  3. Ouvrir chaque fichier dans le bloc-notes et recherchez votre nom de file d'attente (il sera très probablement le fichier qui a été le plus récemment modifié)
  4. Supprimer ce fichier et redémarrez le service de messagerie

Créer une classe de base f ou vos éléments de message de file d'attente et marquez-le [Serializable]. Le cache de charge de l'application d'une liste de tous vos types de messages en utilisant quelque chose comme ceci:

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

Maintenant, vous êtes prêt à recevoir des messages. Mon premier instinct était de rechercher des messages, mais l'API n'aime pas vraiment travailler de cette façon. Donc, je crée un thread d'arrière-plan et appelle la méthode de blocage Receive sur la file d'attente qui reviendra une fois qu'un message est disponible. De là, le décodage message est aussi simple que:

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; 

Et cela devrait être tout ce que vous avez besoin pour bien mis en œuvre, l'intégration typesafe MSMQ!

1

Cela a fonctionné pour moi de lire une file d'attente privée à partir d'une machine distante:

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

formatter Ajout résolu mon problème:

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

Vous pouvez voir exemple de code et d'une bibliothèque de MSMQ sur github: https://github.com/beyazc/MsmqInt

Questions connexes