2012-04-12 3 views
9

У меня есть .NET 3.5 Webservice, размещенный на IIS7.5.Сжатие GZip в WCF WebService

У меня есть клиентское приложение, которое подключается к этому веб-сервису.

Я изменил (в клиентском приложении) метода httpWebRequest.Create добавить automaticDecompression для GZip, но он не работает

WebRequest IWebRequestCreate.Create(Uri uri) 
    { 
     HttpWebRequest httpWebRequest = 
      Activator.CreateInstance(
       typeof(HttpWebRequest), 
       BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, 
       null, 
       new object[] { uri, null }, 
       null) as HttpWebRequest; 

     if (httpWebRequest == null) 
      return null; 

     httpWebRequest.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip, deflate"); 
     httpWebRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; 


     return httpWebRequest; 
    } 

Таким образом, запрос отправляется правильно, ответ кодируется в Gzip (Я вижу его из Скрипачей), но возникает исключение:

Response is not wellformed XML 

(я думаю, что клиент не декодирует ответ)

Если удалить эту строку, как и в MSDN документация

httpWebRequest.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip, deflate"); 

Ответ не GZip закодирован (и в запросе там нет Accept-Encoding заголовок)

+1

МПМ должны иметь возможность добавить поддержку сжатия в любой размещенной службе. Невозможно реализовать сжатие GZip через настраиваемое кодирование. –

+1

Yeh .. ok .. и как я могу использовать сжатие GZip в веб-сервисах WCF? Потому что мне нужно передать много текстовых данных. – AndreaCi

+0

Я прошел через весь этот болезненный процесс около 2-3 лет назад. Я пытался найти решение, которое я нашел, но пока не повезло. +1 тем временем. – leppie

ответ

0

Решенный! Код в вопросе был достаточен для ссылок на службы. Если вы используете веб-ссылки, также добавить линии

my_service_object.EnableDecompression = true; 
0

Одним из возможных путей было бы использовать protobuf для достижения сжатия со службой WCF, если вы контролируете как клиента и сервера.

+0

Протобуф - большая боль для всех, кто его использует, здесь существует множество ограничений. Но любым способом вы не можете использовать его для публичного контракта. –

+0

Вопрос указывает, что они контролируют обе стороны, клиент и сервер. Можете ли вы указать мне на статью «Большая боль» или какое-то резюме, я могу лучше понять, в чем проблема? –

+1

Простой, если вы отправляете пустую коллекцию, вы получите нуль, а не ту же пустую коллекцию. –

4

Я сделал это для переноса объектов DataTable с использованием WCF с DataContract. Вы должны создать DataContract следующим образом:

[DataContract] 
public class WCFDataTableContract 
{ 
    [DataMember] 
    public byte[] Schema { get; set; } 

    [DataMember] 
    public byte[] Data { get; set; } 
} 

Затем я создал Binary конвертер, который будет автоматически конвертировать любой объект в массив байтов, который я затем сжиматься с помощью GZip.

public static class CompressedBinaryConverter 
{ 
    /// <summary> 
    /// Converts any object into a byte array and then compresses it 
    /// </summary> 
    /// <param name="o">The object to convert</param> 
    /// <returns>A compressed byte array that was the object</returns> 
    public static byte[] ToByteArray(object o) 
    { 
     if (o == null) 
      return new byte[0]; 

     using (MemoryStream outStream = new MemoryStream()) 
     { 
      using (GZipStream zipStream = new GZipStream(outStream, CompressionMode.Compress)) 
      { 
       using (MemoryStream stream = new MemoryStream()) 
       { 
        new BinaryFormatter().Serialize(stream, o); 
        stream.Position = 0; 
        stream.CopyTo(zipStream); 
        zipStream.Close(); 
        return outStream.ToArray(); 
       } 
      } 
     } 
    } 

    /// <summary> 
    /// Converts a byte array back into an object and uncompresses it 
    /// </summary> 
    /// <param name="byteArray">Compressed byte array to convert</param> 
    /// <returns>The object that was in the byte array</returns> 
    public static object ToObject(byte[] byteArray) 
    { 
     if (byteArray.Length == 0) 
      return null; 

     using (MemoryStream decomStream = new MemoryStream(byteArray), ms = new MemoryStream()) 
     { 
      using (GZipStream hgs = new GZipStream(decomStream, CompressionMode.Decompress)) 
      { 
       hgs.CopyTo(ms); 
       decomStream.Close(); 
       hgs.Close(); 
       ms.Position = 0; 
       return new BinaryFormatter().Deserialize(ms); 
      } 
     } 
    } 
} 

самосвала это в вашем проекте и позвонить, как это в вашей службы для сжатия:

dt.Data = CompressedBinaryConverter.ToByteArray(data); 

Затем вызовите его, как это на стороне клиента, чтобы преобразовать обратно в объект:

dt = (DataTable)CompressedBinaryConverter.ToObject(wdt.Data); 
+0

Да, это решение, к которому я перехожу ... но есть проблема с этим: исходные и целевые объекты являются экземплярами разных классов (из-за разных пространств имен для веб-сервисов) – AndreaCi

+0

Я помещаю любые определения объектов, которые совместно используются сервером и клиент в отдельную DLL и ссылается на них со стороны моего сервера и клиента. Таким образом, вам нужно только определить/поддерживать его в одном месте, а ваши определения универсальны. – MrWuf

Смежные вопросы