Отправка / получение сжатых GZip MSMQ сообщений в C # - PullRequest
2 голосов
/ 29 августа 2011

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

Однако запись сжатого потока в 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);
}

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

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

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, я фактически обхожу сообщение. Форматирующий объект, который я ни к чему не инициализирую, потому что я использую свой собственный сервис/ Дезертирующий механизм с GZipStream.Однако я не уверен, что это правильный способ сделать это.

Чего мне не хватает?Спасибо!

Ответы [ 3 ]

3 голосов
/ 29 августа 2011

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

2 голосов
/ 29 августа 2011

ОК, я сделал эту работу. Ключ должен был преобразовать распакованный поток на приемнике в массив 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. Спасибо!

1 голос
/ 29 августа 2011

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

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