如何从WCF服务中止流而不读取它?

时间:2012-07-29 14:39:00

标签: c# wcf stream wshttpbinding mtom

这是我上周一直在调查的问题,无法找到任何解决方案。发现帖子提出同样但从未得到答案,希望这也会对其他人有所帮助。

我有一个WCF服务,它返回一个包含stream的对象。我使用basicHttpBinding进行流式传输和Mtom将其发送给客户端。

客户端调用WCF服务并在收到响应对象后立即关闭代理。

接下来,客户端读取从WCF服务获取的流并将其写入本地磁盘上的文件。所有这一切都很好。

我的问题是客户端想要中止操作并停止从WCF服务下载数据。 如果我在流上调用.close(),例如:serverReply.DataStream.Close();则它会阻止并从WCF服务读取整个流,直到结束,然后继续。流可能非常大,网络并不总是很快。

这对于两种网络资源的使用都是非常不受欢迎的,这基本上浪费在不再使用的数据上。由于basicHttpBinding仅允许两个并发TCP连接(默认情况下)到WCF服务服务器,因此它会阻止其他连接尝试,直到读取流直到结束。

我可以增加并发连接的数量,但这将是一个糟糕的解决方案,因为它会为麻烦创建一个开放。

例如,20个中止的下载仍在下载数据以将其丢弃。我需要完全停止转移。

在客户端上,流对象只是一个普通的Stream类,所以它只有close方法,没有别的。

在代理对象上调用.close().abort()没有帮助,也没有使用.dispose()或任何其他方法销毁它。 在服务器端,我处理OperationContext.OperationCompleted事件,但在读取stream的数据直到结束时才会触发。

所以问题是,如何关闭/中止流而不完全读取它?

3 个答案:

答案 0 :(得分:1)

经过调查,我发现WCF客户端将继续从流中读取,直到closeTimeout被删除,然后它将中止连接。您可以减少客户端上的closeTimeout以最小化问题。

注意:您应该将处理流的代码包装到try / catch块中。 stream.Dispose()方法将抛出TimeoutException,它会制定not throwing exceptions in Dispose method的准则。

答案 1 :(得分:0)

您是否尝试过玩binding.MaxBufferSize
您是否尝试过使用app.config文件设置,例如:

<bindings>
  <wsHttpBinding>
    <binding name="default" maxReceivedMessageSize="2147483647"  maxBufferPoolSize="2147483647" 
             closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" >
      <readerQuotas  maxArrayLength="2147483647" maxBytesPerRead="4096" maxNameTableCharCount="16384"
                     maxDepth="64" maxStringContentLength="2147483647" />
    </binding>

  </wsHttpBinding>
</bindings>

我会尽量减少缓冲区长度的超时,并尝试中止或关闭,看看会发生什么。

答案 2 :(得分:0)

我认为你只是在关闭后才收到缓冲区。您应该将maxBufferSize设置为较低的值。

您可能还希望通过包装流并覆盖读取来限制服务器上读取的数据量。如果您的带宽较低的客户端使用较小的块,并从read方法返回相应的计数以匹配您实际读取的数量。这会限制缓冲区的填充率。

我对这个主题的测试涉及到我编写NeverEndingStream并始终返回数据。在某些时候,我在客户端上调用close,然后几乎立即在服务器上调用了close。这表明缓冲区只是被清空了,因为显然它永远无法读到我的流直到最后。

如果您仍遇到问题,我建议您在已覆盖的流上跟踪Read方法的时间。如果currentReadtime - lastReadTime是&gt; x然后你可能会调用Close并抛出异常。这肯定会杀了它。