MSMQ + C #, получение сообщения с закодированным телом byte [] ведет себя по-разному в Windows 7 и Windows XP - PullRequest
2 голосов
/ 03 мая 2011

У меня есть приложение, которое отображает содержимое сообщений в очереди сообщений MSMQ. Существует проблема с MSMQ в Windows 7, не сохраняющая истинный тип объекта данных в теле сообщения. В этом примере я отправляю byte [], а затем, когда я его получаю, это уже не байтовый массив, а упакованный документ XML-контейнера. В Windows XP у меня никогда не было этой проблемы, и свойство Message.Body всегда было правильно установлено в байт [].

Вот код сжатия:

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

Вот содержимое сообщения для тестового сообщения. Это заканчивается как XML-документ, который упаковывает закодированные двоичные данные .: <?xml version="1.0"?>..<base64Binary>H4sIAAAAAAAEAO29B2AcSZYlJi9tynt/SvVK1+B0oQiAYBMk2JBAEOzBiM3mkuwdaUcjKasqgcplVmVdZhZAzO2dvPfee++999577733ujudTif33/8/XGZkAWz2zkrayZ4hgKrIHz9+fB8/Ih63edMefTsvy2rv8V3+4/8ByygBlxMAAAA=</base64Binary>


Вот код декомпрессии, который он использует:

        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;

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

Я хотел бы отметить, что я устанавливаю средство форматирования сообщения, которое является первым шагом к тому, чтобы тело автоматически помещало "box" и "unbox" в очередь.

В Windows XP m.Body.GetType () == byte [], как и ожидалось. Но в Windows 7 m.Body.GetType () == XmlElement, то есть оболочка XML. Он больше не «распаковывает» сообщение.

Нам нужно сделать что-то по-другому? Однажды мы работали над этим для отправки строк, как вы можете видеть в конце функции приема, но я хотел бы найти реальный ответ, почему этот код ведет себя по-разному в Windows 7.

Ответы [ 2 ]

7 голосов
/ 19 ноября 2011

Используйте свойство Message.BodyStream, если вы хотите отправить массив байтов:

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);
2 голосов
/ 27 июня 2012

Используйте Message.BodyStream свойство для отправки и получения сообщения, посмотрите код ниже, который вы можете отправить и получить byte[], используя его.

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