Message Queue Error: impossible de trouver un formateur capable de lire le message

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

  •  19-08-2019
  •  | 
  •  

Question

J'écris des messages dans une file d'attente de messages en C # comme suit:

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

J'essaie de lire les messages comme suit:

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

Toutefois, je reçois un message d'erreur indiquant: "Impossible de trouver un outil de formatage capable de lire ce message."

Qu'est-ce que je fais de travers?

Était-ce utile?

La solution

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
}

Autres conseils

Ou vous pouvez utiliser

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

vous pouvez essayer de lire le flux de corps du message à la place du corps, comme ceci:

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

La file d'attente doit également être configurée.

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

Il semble que la sérialisation n’est effectuée que lors de l’accès à la propriété Body de la classe Message. Tant que vous accédez à la propriété Body après avoir défini le bon formateur dans 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;

Tout le monde ici a fourni un travail fantastique en apportant des solutions et, après avoir moi-même fini de lutter contre ce problème, je voulais mettre mon propre 2c et montrer la solution que j'ai proposée qui fonctionne très bien.

Tout d'abord, lorsque la file d'attente est créée, je m'assure d'ouvrir les autorisations de la manière suivante (la sécurité de la file d'attente ne me concerne pas dans le contexte de notre application ... cette décision est calculée):

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

Sans cette ligne, je recevrais toutes sortes d'erreurs inaccessibles et je ne pourrais même pas parcourir la file d'attente à partir de l'écran de gestion de l'ordinateur. Incidemment, si cela vous arrive et que vous vous demandez comment éliminer la file d'attente à laquelle vous n'avez pas accès, il suffit de:

  1. Arrêter le service "Message Queuing"
  2. Allez vers " C: \ Windows \ System32 \ msmq \ storage \ lqs "
  3. Ouvrez chaque fichier dans le bloc-notes et recherchez votre nom de file d'attente (ce sera probablement le fichier le plus récemment modifié)
  4. Supprimez ce fichier et redémarrez le service de messagerie

Créez une classe de base pour vos éléments de message de file d'attente et marquez-la [Serializable]. Lors du chargement de l’application, mettez en cache 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);

Vous êtes maintenant prêt à recevoir des messages. Mon premier instinct a été de rechercher des messages, mais l’API n’aime pas vraiment travailler de cette façon. Je crée donc un fil d’arrière-plan et appelle la méthode de blocage Receive sur la file d’attente qui sera renvoyée dès qu’un message sera disponible. À partir de là, décoder le 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 c’est tout ce dont vous avez besoin pour une implémentation parfaite, l’intégration MSMQ typesafe!

Cela m'a permis de lire une file d'attente privée à partir d'un ordinateur distant:

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

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

L'ajout d'un formateur a 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 un exemple de code et la bibliothèque msmq sur github: https://github.com/beyazc/MsmqInt

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top