2012-04-12 12 views
9

Ich habe einen .NET 3.5 Webservice auf IIS7.5 gehostet.GZip-Komprimierung in WCF WebService

Ich habe eine Client-Anwendung, die sich mit diesem Webservice verbindet.

I (in Client-Anwendung) der httpWebRequest.Create Methode geändert automaticDecompression für GZIP hinzufügen, aber es funktioniert nicht

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

Auf diese Weise wird die Anfrage korrekt gesendet wird, wird die Antwort in gzip kodiert (ich sehe es von Fiddler), aber eine Ausnahme auftritt:

Response is not wellformed XML 

(ich denke, der Client entschlüsselt die Antwort nicht)

Wenn ich diese Zeile entfernen, wie in MSDN-Dokumentation

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

Die Antwort ist nicht GZIP kodiert (und in der Anfrage gibt es keine Accept-Encoding-Header)

+1

Die IIS eine Möglichkeit Kompression Unterstützung hinzufügen zu einem gehosteten Dienst haben sollte. Es gibt keine Möglichkeit, die GZip-Komprimierung durch benutzerdefiniertes Codieren zu implementieren. –

+1

Yeh .. ok .. und wie kann ich GZip-Komprimierung in WCF-Webservices verwenden? Weil ich viele Textdaten übertragen muss. – AndreaCi

+0

Ich ging durch diesen ganzen schmerzhaften Prozess ungefähr 2-3 Jahre zurück. Ich habe versucht, die Lösung zu finden, die ich gefunden habe, aber bisher kein Glück. +1 in der Zwischenzeit. – leppie

Antwort

0

Gelöst !! Der Code in der Frage war genug für Service-Referenzen. Wenn Sie Web-Referenzen verwenden, fügen Sie auch die Linie

my_service_object.EnableDecompression = true; 
0

Eine Möglichkeit wäre protobuf zu verwenden Kompression mit dem WCF-Dienst zu erreichen, wenn Sie beide Kontrolle Client und Server.

+0

Der Protobuf ist ein großer Schmerz für jeden, der ihn benutzt hat, eine Menge Einschränkungen gibt es hier. Aber irgendwie können Sie es nicht für einen öffentlichen Auftrag verwenden. –

+0

Die Frage zeigt, dass sie die Kontrolle über beide Seiten, Client und Server, haben. Kannst du mich auf den "großen Schmerz" -Artikel oder eine Zusammenfassung hinweisen, kann ich mir eine bessere Vorstellung von den Problemen machen? –

+1

Das einfache ist, wenn Sie eine leere Sammlung senden, erhalten Sie stattdessen Null die gleiche leere Sammlung. –

4

Ich habe dies getan, um DataTable-Objekte mit WCF mit DataContract zu übertragen. Sie müssen die Datacontract wie folgt erstellen:

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

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

Dann habe ich ein Binär-Wandler, der jedes Objekt ein Byte-Array automatisch konvertiert, die ich dann mit gzip komprimieren kann.

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

Dump dieses Projekt in und in der Service wie folgt aufrufen zu komprimieren:

dt.Data = CompressedBinaryConverter.ToByteArray(data); 

es dann wie diese Seite auf Ihrem Client aufrufen, um ein Objekt zu konvertieren zurück:

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

Ja, es ist die Lösung, zu der ich gehe .. aber es gibt ein Problem damit: Quell- und Zielobjekte sind Instanzen verschiedener Klassen (wegen unterschiedlicher Namespaces für Webservices) – AndreaCi

+0

Ich setze alle Objektdefinitionen, die zwischen dem Server und Client in eine separate DLL und referenzierte sie sowohl von meiner Server-und Client-Seite. Auf diese Weise müssen Sie es nur an einem Ort definieren/verwalten und Ihre Definitionen sind universell. – MrWuf

Verwandte Themen