IEnumerable、流和 WCF
IEnumerable, streams and WCF
我正在编写一项服务,可向客户提供 return 大量数据集。理想情况下,我想要 return 一个实体的 IEnumerable 因为我想要在服务和客户端上的惰性的性能优势。我也希望能够压缩流以减少带宽。
我能够将 IEnumerable 序列化为流并利用 GZip 对其进行压缩。我也能够成功反序列化流。但是,我的实现没有实现我的目标中的惰性部分。
我已经阅读了与我的问题类似的概念的解决方案,但它们都涉及 returning 一个 IEnumerable 字节。理想情况下,我希望客户端接收实体的 IEnumerable 并能够在反序列化时生成 return 它。
[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;
}
我想您可能对 IEnumerable 有点困惑。但是,除此之外,您确实应该将研究重点放在 WCF Streaming
查看此博客 Custom WCF Streaming and its associated example。它基本上封装了你想要的一切,还使用了BinaryFormatter
、
如果您想更进一步,您可以使用 Protocol Buffer Protobuf-net 或添加您自己的 ad-hock 压缩。但是,我将这些细节留给您。
Basic idea is : we will have two threads, one thread will execute the
complex database query and another thread will stream database rows to
the clients. So we will alter the database query such that it returns
only 1000 rows at time. And modify the WCF service to stream these
1000 rows to client. While WCF service is streaming database rows to
the client, at the same time on a different thread, WCF Service will
run the database query again to get the next 1000 rows. This way as
soon as the WCF Service finishes streaming rows to the client, the
next set of rows are available to stream to the client
- WCF 客户端调用 WCF 服务
- WCF 服务执行数据库查询
- 数据库 returns 数据集到 WCF 服务
- WCF 服务响应
- WCF 服务执行的第二个数据库查询
- WCF 流响应
我正在编写一项服务,可向客户提供 return 大量数据集。理想情况下,我想要 return 一个实体的 IEnumerable 因为我想要在服务和客户端上的惰性的性能优势。我也希望能够压缩流以减少带宽。
我能够将 IEnumerable 序列化为流并利用 GZip 对其进行压缩。我也能够成功反序列化流。但是,我的实现没有实现我的目标中的惰性部分。
我已经阅读了与我的问题类似的概念的解决方案,但它们都涉及 returning 一个 IEnumerable 字节。理想情况下,我希望客户端接收实体的 IEnumerable 并能够在反序列化时生成 return 它。
[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;
}
我想您可能对 IEnumerable 有点困惑。但是,除此之外,您确实应该将研究重点放在 WCF Streaming
查看此博客 Custom WCF Streaming and its associated example。它基本上封装了你想要的一切,还使用了BinaryFormatter
、
如果您想更进一步,您可以使用 Protocol Buffer Protobuf-net 或添加您自己的 ad-hock 压缩。但是,我将这些细节留给您。
Basic idea is : we will have two threads, one thread will execute the complex database query and another thread will stream database rows to the clients. So we will alter the database query such that it returns only 1000 rows at time. And modify the WCF service to stream these 1000 rows to client. While WCF service is streaming database rows to the client, at the same time on a different thread, WCF Service will run the database query again to get the next 1000 rows. This way as soon as the WCF Service finishes streaming rows to the client, the next set of rows are available to stream to the client
- WCF 客户端调用 WCF 服务
- WCF 服务执行数据库查询
- 数据库 returns 数据集到 WCF 服务
- WCF 服务响应
- WCF 服务执行的第二个数据库查询
- WCF 流响应