I\'m writing messages to a Message Queue in C# as follows:
queue.Send(new Message(\"message\"));
I\'m trying to read the messages as follow
you could try reading the bodystream of the message instead of the body, like this:
StreamReader sr = new StreamReader(m.BodyStream);
string messageBody = "";
while (sr.Peek() >= 0)
{
messageBody += sr.ReadLine();
}
I solved the problem by adding a formatter to each message. Adding a formatter to the queue didn't work.
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
}
This worked for me to read a private queue from a remote machine:
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();
Don't use Microsoft Message Queue (MSMQ). Just don't. It is both deprecated, and bottom of the pile in terms of anything useful, performant or even remotely well designed.
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 must be set Formatter too.
myQueue.Formatter = new XmlMessageFormatter(new String[] { "System.String,mscorlib" });
Everyone here has done a fantastic job at providing solutions, and having just finished battling this problem myself I wanted to throw my own 2c in and show the solution I came up with that works very well.
Firstly when the queue is created I make sure I open up the permissions like so (I'm not concerned about queue security in the context of our application... this is a calculated decision):
queue.SetPermissions("Everyone", MessageQueueAccessRights.FullControl, AccessControlEntryType.Set);
Without that line I would receive all sorts of inaccessible errors and couldn't even browse the queue from the computer management screen. Incidentally if that happens to you and you're wondering how to kill the queue that you don't have access to just:
Create a base class for your queue message items and mark it [Serializable]. On application load cache a list of all your message types using something like this:
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);
Now you're ready to start receiving messages. My first instinct was to poll for messages, but the api doesn't really like working that way. So I create a background thread and call the blocking method Receive on the queue which will return once a message is available. From there decoding the message is as simple as:
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;
And that should be all you need to get nicely implemented, typesafe MSMQ integration!
It seems that the serialization is only done when accessing the Body
property of the Message
class. As long as you access the Body
property after you set on the message the right Formatter
it works fine.
If you prefer not to create a Formatter
for each message you can set the Formatter
on the queue and for each message (before accessing the Body property) set the Formatter
property from the Formatter
of the queue.
_queue.Send(new Message() { Formatter = _queue.Formatter, Body = myData } );
var msg = _qeueu.Receive();
msg.Formatter = _queue.Formatter;
var myObject = (MyClass) msg.Body;