【发布时间】:2018-03-18 00:30:21
【问题描述】:
我正在编写一个向客户端返回大量数据的服务。理想情况下,我想返回一个实体的 IEnumerable,因为我想要服务和客户端上的惰性带来的性能优势。我还希望能够压缩流以减少带宽。
我能够将 IEnumerable 序列化为流并利用 GZip 对其进行压缩。我还能够成功反序列化流。但是,我的实现并没有实现我的目标中的懒惰部分。
我已经阅读了与我的问题类似的概念的解决方案,但它们都涉及返回一个 IEnumerable 字节。理想情况下,我希望客户端接收 IEnumerable 的实体,并能够在反序列化时将其返回。
[DataContract]
public class Entity
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Code { get; set; }
[DataMember]
public string Description { get; set; }
}
[Test]
public void TestSerialEnumGzip()
{
var e = GetEnum();
var s = SerializeToStreamGzip(e);
Console.WriteLine($" TestSerialGzip stream size {s.Length}");
var b = DeserializeFromStreamGzip<IEnumerable<Entity>>(s);
}
private IEnumerable<Entity> GetEnum()
{
for (var x = 0; x < 10; ++x)
{
Console.WriteLine($"yielding {x}");
yield return new Entity { Id = x, Code = x.ToString(), Description = x.ToString() };
}
}
private Stream SerializeToStreamGzip<T>(T toSerialize)
{
var s = new MemoryStream();
using (var gz = new GZipStream(s, CompressionMode.Compress, true))
{
var ser = new DataContractSerializer(typeof(T));
ser.WriteObject(gz, toSerialize);
}
s.Seek(0, SeekOrigin.Begin);
return s;
}
private T DeserializeFromStreamGzip<T>(Stream stream)
{
var ser = new DataContractSerializer(typeof(T));
var gz = new GZipStream(stream, CompressionMode.Decompress);
var result = (T)ser.ReadObject(gz);
return result;
}
【问题讨论】:
-
解释你想从懒惰中得到什么
-
However, my implementation doesn't achieve the Laziness part of my goal.你是怎么得出这个结论的? -
@MichaelRandall 在服务器上,整个数据集可能需要一段时间才能收集,我希望能够尽快返回流。这样,即使服务可能尚未准备好所有数据,客户端也可以开始接收数据。这还有一个额外的好处,即服务不需要内存来打包整个数据集,
-
@mjwills 产生控制台写入发生在流大小写入之前。这意味着 IEnumerable 在客户端接收之前在服务上进行了迭代。
-
您尝试做的事情实际上要复杂得多。而不是让
SerializeToStreamGzip在一个步骤中序列化来自e的所有元素,您需要一个接一个地序列化它们,并以某种方式找到一种方法,只有在您的 Stream 的句柄返回到之后才能继续WCF。因此,MemoryStream的实例(作为单个缓冲区,预先)是不够的,您必须返回自己的Stream实现,WCF 可以为此不断调用Read方法来获取后续块。我可能会首先寻找可以做到这一点的库
标签: c# wcf stream ienumerable gzipstream