MSMQ + C#, receiving a message with encoded byte[] body behaves differently on Windows 7 vs. Windows XP
I have an application that displays the contents of messages in an MSMQ message queue. There is a problem with MSMQ on Windows 7 not preserving the true object type of the data in the message body. In the example, I send a byte[], and then later when I receive it, it's no longer a byte array, but the wrapped XML container document. In Windows XP I have never had this problem, and the Message.Body property has always correctly been set to a byte[].
Here is the compression code:
public void SendWithCompression(string Message)
{
try
{
// Compress the message data in memory.
byte[] UncompressedData = Encoding.UTF8.GetBytes(Message);
byte[] CompressedData = null;
MemoryStream s = new MemoryStream();
using (GZipStream z = new GZipStream(s, CompressionMode.Compress))
{
z.Write(UncompressedData, 0, UncompressedData.Length);
}
CompressedData = s.ToArray();
if (_Transaction != null)
{
_Transaction.Begin();
base.Send(CompressedData, _Transaction);
_Transaction.Commit();
}
else
{
base.Send(CompressedData);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Here is the message contents for a test message. It ends up as an XML document that wraps the encoded binary data.:
<?xml version="1.0"?>..<base64Binary>H4sIAAAAAAAEAO29B2AcSZYlJi9tynt/SvVK1+B0oQiAYBMk2JBAEOzBiM3mkuwdaUcjKasqgcplVmVdZhZAzO2dvPfee++999577733ujudTif33/8/XGZkAWz2zkrayZ4hgKrIHz9+fB8/Ih63edMefTsvy2rv8V3+4/8ByygBlxMAAAA=</base64Binary>
Here is the decompression code it uses:
String Data;
//Get message and format XML
System.Messaging.Message m = MessagesList[ListIndex].Tag;
m.Formatter = new XmlMessageFormatter(new Type[]
{
typeof(string), // Send raw plain strings
typeof(byte[]), // Array of binary data
typeof(XmlNode) // Xml document
});
m.BodyStream.Position = 0;
Data = m.Body.ToString();
if (m.Body.GetType() == typeof(byte[]))
{
try
{
// The message body is an array of binary data.
// Assume it is a GZIP stream of compressed data.
byte[] CompressedData = (byte[])m.Body;
byte[] UncompressedData = null;
开发者_如何学JAVA // Decompress it.
MemoryStream s = new MemoryStream(CompressedData);
using (GZipStream z = new GZipStream(s, CompressionMode.Decompress))
{
UncompressedData = MyExtensions.ReadRemainingBytes(z);
}
// Turn the bytes back into a string.
Data = Encoding.UTF8.GetString(UncompressedData);
}
catch
{
Data = "Unknown binary data: " +
BitConverter.ToString((byte[])m.Body, 0);
}
}
if (m.Body.GetType() == typeof(XmlElement))
{
XmlElement el = (XmlElement)m.Body;
if (el.Name == "string")
Data = el.InnerText;
else
Data = el.OuterXml;
}
I would like to point out that I am setting the Formatter of the message, which is the first step to getting the body to automatically "box" and "unbox" in the queue.
In Windows XP, m.Body.GetType() == byte[], like expected. But, in Windows 7, m.Body.GetType() == XmlElement, i.e. the wrapper XML. It no longer "unboxes" the message.
Do we need to do something differently? We have worked around it once for sending strings, as you can see at the end of the receive function, but I would like to find a real answer for why this code behaves differently on Windows 7.
Use the Message.BodyStream property if you want to send an array of bytes:
System.Messaging.MessageQueue queue = new MessageQueue(queueFormatName, false, true, QueueAccessMode.Send);
System.Messaging.Message msg = new System.Messaging.Message();
msg.BodyStream = new MemoryStream(buffer);
queue.Send(msg, MessageQueueTransactionType.Single);
Use Message.BodyStream
property for sending and receiving message, take a look at code below you can send and receive byte[]
using it.
public void SendMessage()
{
MessageQueue myQueue = new MessageQueue(".\\QUEUE");
byte[] msg = new byte[2];
msg[0] = 29;
// Send the array to the queue.
Message msg1 = new Message();
msg1.BodyStream = new MemoryStream(msg);
messageQueue.Send(msg1);
}
public void ReceiveMessage()
{
MessageQueue myQueue = new MessageQueue(".\\QUEUE");
Message myMessage =myQueue.Receive();
byte[] msg = ReadFully(myMessage.BodyStream);
}
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
精彩评论