Я пытаюсь отправить большие объекты (> 30 МБ) в очередь MSMQ. Из-за большого количества данных, которые мы собираемся отправить, идея заключалась в том, чтобы сжать объекты перед отправкой, а затем распаковать их на принимающей стороне.

Однако запись сжатого потока в свойство message.BodyStream, похоже, работает, но не считывает его оттуда. Я не знаю, что случилось.

Message l_QueueMessage = new Message();
l_QueueMessage.Priority = priority;

using (MessageQueue l_Queue = CreateQueue())
{
    GZipStream stream = new GZipStream(l_QueueMessage.BodyStream, CompressionMode.Compress);

    Formatter.Serialize(stream, message);

    l_Queue.Send(l_QueueMessage);
}

Formatter - это глобальное свойство типа BinaryFormatter. Это используется для сериализации / десериализации в тип объекта, который мы хотим отправить / получить, например. «ПродуктЭлемент».

Принимающий конец выглядит так:

GZipStream stream = new GZipStream(l_Message.BodyStream, CompressionMode.Decompress);

object decompressedObject = Formatter.Deserialize(stream);

ProductItem l_Item = decompressedObject as ProductItem;

m_ProductReceived(sender, new MessageReceivedEventArgs<ProductItem>(l_Item));

l_ProductQueue.BeginReceive();

Я получаю EndOfStreamException "{"Unable to read beyond the end of the stream."} при попытке десериализации в System.IO.BinaryReader.ReadByte ()

Используя свойство messageBodyStream, я фактически обхожу message.Formatter, который я ни для чего не инициализирую, потому что я использую свой собственный механизм ser / deser с GZipStream. Однако я не уверен, что это правильный способ.

Что мне не хватает? Благодарность!

2
John 29 Авг 2011 в 09:29

3 ответа

Лучший ответ

Хорошо, я сделал эту работу. Ключевым моментом было преобразование распакованного потока на приемнике в массив byte []. Затем заработала десериализация.

Код отправителя (обратите внимание, что поток закрывается перед отправкой сообщения):

using (MessageQueue l_Queue = CreateQueue())
{
    using (GZipStream stream = new GZipStream(l_QueueMessage.BodyStream, CompressionMode.Compress, true))
    {
        Formatter.Serialize(stream, message);
    }

    l_Queue.Send(l_QueueMessage);
}

Принимающая сторона (обратите внимание, как я конвертирую поток в байт [], а затем десериализую):

using (GZipStream stream = new GZipStream(l_QueueMessage.BodyStream, CompressionMode.Decompress))
{
    byte[] bytes = ReadFully(stream);

    using (MemoryStream ms = new MemoryStream(bytes))
    {
        decompressedObject = Formatter.Deserialize(ms);
    }
}

Тем не менее, не знаю, почему это работает с использованием функции ReadFully (), а не Stream.CopyTo (). Кто-нибудь?

Кстати, ReadFully () - это функция, которая создает байт [] из потока. Я должен отдать должное Джону Скиту на странице http://www.yoda.arachsys.com/ csharp / readbinary.html. Спасибо!

2
John 31 Авг 2011 в 12:22

В исходном коде проблема заключается в том, что вам нужно закрыть GZipStream, чтобы нижний колонтитул GZip был написан правильно, и только после этого вы можете его отправить. Если вы этого не сделаете, вы отправите байты, которые не могут быть десериализованы. Вот почему ваш новый код, в котором отправка выполняется позже, работает.

3
Tsabo 29 Авг 2011 в 10:28

Попробуйте разделить сжатие и отправку:

byte[] binaryBuffer = null;
using (MemoryStream compressedBody = new MemoryStream()) 
{
    using(GZipStream stream = new GZipStream(compressedBody, CompressionMode.Compress))
    {
        Formatter.Serialize(compressedBody, message); 
        binaryBuffer = compressedBody.GetBuffer();
    }
}

using (MessageQueue l_Queue = CreateQueue())        
{            
    l_QueueMessage.BodyStream.Write(binaryBuffer, 0, binaryBuffer.Length);
    l_QueueMessage.BodyStream.Seek(0, SeekOrigin.Begin);
    l_Queue.Send(l_QueueMessage);
}
1
rudolf_franek 29 Авг 2011 в 11:34