WCF WebService 中的 GZip 压缩
本文关键字:压缩 GZip 中的 WebService WCF | 更新日期: 2023-09-27 18:30:58
我有一个托管在IIS7.5上的.NET 3.5 Web服务。
我有一个连接到此 Web 服务的客户端应用程序。
我更改了(在客户端应用程序中)httpWebRequest.Create方法来为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 编码(我从 Fiddler 看到它),但发生了异常:
Response is not wellformed XML
(我认为客户端不会解码答案)
如果我删除此行,如 MSDN 文档中所示
httpWebRequest.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip, deflate");
答案不是 GZip 编码(并且在请求中没有 ACCEPT-ENCODING 标头)
我这样做是为了使用 WCF 和 Datacontract 传输 DataTable 对象。 您必须按如下方式创建数据协定:
[DataContract]
public class WCFDataTableContract
{
[DataMember]
public byte[] Schema { get; set; }
[DataMember]
public byte[] Data { get; set; }
}
然后我创建了一个二进制转换器,它会自动将任何对象转换为字节数组,然后我可以使用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);
一种可能的方法是,如果您同时控制客户端和服务器,则使用 protobuf 通过 WCF 服务实现压缩。
解决了!!问题中的代码足以用于服务引用。如果您使用的是 Web 引用,请同时添加该行
my_service_object.EnableDecompression = true;