在具有消息安全性的WCF中使用wsHttp传输大量有效数据(序列化对象)

在具有消息安全性的WCF中使用wsHttp传输大量有效数据(序列化对象),wcf,large-data-volumes,wshttpbinding,chunking,netdatacontractserializer,Wcf,Large Data Volumes,Wshttpbinding,Chunking,Netdatacontractserializer,我有一个案例,需要使用WCF和wsHttp传输大量的序列化对象图(via)。我正在使用消息安全性,并希望继续这样做。使用此设置,我希望传输序列化对象图,它有时可能接近300MB左右,但当我尝试这样做时,我开始看到System.InsufficientMemoryException类型的异常出现 经过一点研究,在WCF中,默认情况下服务调用的结果包含在一条消息中,该消息默认包含序列化数据,并且该数据在服务器上默认缓冲,直到整个消息完全写入。因此,内存异常是由以下事实引起的:由于缓冲区已满,服务器正

我有一个案例,需要使用WCF和wsHttp传输大量的序列化对象图(via)。我正在使用消息安全性,并希望继续这样做。使用此设置,我希望传输序列化对象图,它有时可能接近300MB左右,但当我尝试这样做时,我开始看到System.InsufficientMemoryException类型的异常出现

经过一点研究,在WCF中,默认情况下服务调用的结果包含在一条消息中,该消息默认包含序列化数据,并且该数据在服务器上默认缓冲,直到整个消息完全写入。因此,内存异常是由以下事实引起的:由于缓冲区已满,服务器正在耗尽允许分配的内存资源。我遇到的两个主要建议是使用流式处理或分块处理来解决此问题,但我不清楚这涉及到什么,以及在我当前的设置(wsHttp/NetDataContractSerializer/Message Security)中是否可以使用这两种解决方案。到目前为止,我理解使用流式消息安全性是行不通的,因为消息加密和解密需要处理整个数据集,而不是部分消息。然而,分块听起来似乎是可能的,但我不清楚在我列出的其他约束条件下如何实现。如果有人能就可用的解决方案以及如何实施提供一些指导,我将不胜感激

我应该补充一点,在我的例子中,我真的不担心与其他客户机的互操作性,因为我们拥有并控制通信的每一方,并使用共享接口模式将数据传输到任何一方。因此,我愿意接受任何与使用具有消息安全性的wsHttp传输使用NetDataContractSerializer序列化的对象图的限制条件相适应的想法,我更喜欢一种不必大幅更改现有服务和周围基础设施的解决方案

相关资源:

我还对可以对这些数据进行的任何类型的压缩感兴趣,但看起来我最好在传输级别进行压缩,一旦我可以转换到.NET4.0,这样如果我正确理解这一点,客户端将自动支持gzip头

更新(2010-06-29): 关于我如何得出缓冲消息太大导致我的问题的结论的一些历史记录。最初我在测试时看到了下面的内容

基础连接已关闭:连接意外关闭

最后,在运行这个程序并进行更多的日志记录之后,我发现了导致指定消息出现问题的底层异常

未能分配268435456字节的托管内存缓冲区。可用内存量可能较低

它起源于以下方法

System.ServiceModel.Diagnostics.Utility.AllocateByteArray(Int32大小)

换句话说,失败来自于分配数组。当将相同的数据序列化到磁盘时,它会占用146MB左右的空间,如果我将其减半,那么我就不会再收到错误,但是我没有深入研究破坏缓冲区的特定阈值以及它是否特定于我的系统

更新(2010-12-06): 我想在这一点上,我在寻找一些澄清如下。我的理解是,默认情况下,使用具有消息安全性的WCF wsHttp,在将响应发送回客户端之前,需要在服务器上缓冲整个消息(通常是我返回的整个数据集),从而导致我的问题

可能的解决办法:

  • 限制数据大小-通过使用某种形式的压缩、编码或限制使用某种类似分页的方法返回的实际数据,以避免消耗传出缓冲区的最大容量
  • 流-允许以流方式通过WCF发送大量数据,但这与wsHttp或MessageSecurity不兼容,因为这些技术需要缓冲所有数据
  • 分块通道-允许将数据分解为单独的消息,但目前我不确定这对服务契约设计有何限制,以及是否仍然可以将wsHttp与消息绑定一起使用

限制我可以返回的数据只能在一定程度上起作用,并且与流式传输选项一样,这些选项需要在WCF服务调用之外编写大量较低级别的工作。因此,我想我需要知道的是,分块通道的任何可能实现是否可以通过允许在服务器上将单个数据集分解为单独的消息,然后在客户机上以一种不必更改现有服务的接口/形状的方式拼接在一起,从而绕过大型消息问题以一种对每个服务实现的客户机和服务器部分几乎隐藏流程的方式进行压缩,同时仍然使用消息安全性和wsHttp。如果分块通道要求我重新编写服务契约以公开流,那么我看不出这与流解决方案有什么区别。如果有人能简单地为我回答这些问题,我将奖励他们奖金,并将其标记为答案。

如果您仍想使用消息安全性,我建议您使用MTOM优化传输消息所需的网络带宽,以及在应用安全性时使用较小内存缓冲区的分块通道。否则,WCF将尝试在内存中加载整个消息以应用安全性,因此您将获得I
int transferSize = 5000000; // 5MB
byte[] compressed = ...;
var mem = new System.IO.MemoryStream(compressed);

for(int i = 0; i < compressed .length; i+= transferSize )
{
    byte[] buffer = new byte[transferSize];
    mem.Read(buffer, i, compressed);
    mem.Flush();
    sendFragmentToWCF(buffer);
}
[WebMethod]
public void GetSerializedObject()
{
    string path = @"X:\temp.tmp";

    var serializer = new  System.Runtime.Serialization.NetDataContractSerializer();
    var file = new System.IO.FileStream(path, System.IO.FileMode.CreateNew);

    try
    {
        serializer.Serialize(file, ...);
        this.Context.Response.TransmitFile(path);
        this.Context.Response.Flush();
    }
    finally
    {
        file.Flush();
        file.Close();
        file.Dispose();
        System.IO.File.Delete(path);
    }
}