简体   繁体   English

WCF WebService中的GZip压缩

[英]GZip compression in WCF WebService

I have a .NET 3.5 Webservice Hosted on IIS7.5. 我在IIS7.5上有一个.NET 3.5 Webservice。

I have a client application who connects to this webservice. 我有一个连接到此Web服务的客户端应用程序。

I changed (in client application) the httpWebRequest.Create method to add automaticDecompression for GZip but it isn't working 我更改了(在客户端应用程序中)httpWebRequest.Create方法为GZip添加automaticDecompression但是它不起作用

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

In this way the request is sent correctly, the answer is encoded in gzip (I see it from Fiddler), but an exception occurs: 通过这种方式正确发送请求,答案以gzip编码(我从Fiddler看到),但发生异常:

Response is not wellformed XML

(I think the client doesn't decode the answer) (我认为客户端没有解码答案)

If I remove this row, as in MSDN documentation 如果我删除此行,如在MSDN文档中

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

The answer is not GZip encoded (and in the request there's no ACCEPT-ENCODING header) 答案不是GZip编码(在请求中没有ACCEPT-ENCODING标头)

I've done this to transfer DataTable objects using WCF with DataContract. 我这样做是为了使用带有DataContract的WCF传输DataTable对象。 You have to create the DataContract as follows: 您必须按如下方式创建DataContract:

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

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

Then I created a Binary Converter that will automatically convert any object to a byte array that I can then compress using GZip. 然后我创建了一个二进制转换器,它会自动将任何对象转换为字节数组,然后我可以使用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);
            }
        }
    }
}

Dump this in your project and call like this in your Service to compress: 将其转储到您的项目中并在您的服务中调用以进行压缩:

dt.Data = CompressedBinaryConverter.ToByteArray(data);

Then call it like this on your client side to convert back to an object: 然后在客户端调用它来转换回对象:

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

如果您同时控制客户端和服务器,一种可能的方法是使用protobuf通过WCF服务实现压缩。

Solved!! 解决了!! The code in the question was enough for Service references. 问题中的代码足以用于服务引用。 If you are using Web references, add also the line 如果您使用的是Web引用,请同时添加该行

my_service_object.EnableDecompression = true;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM