为什么WCF在Close()上读取输入流到EOF?

ane*_*son 5 streaming wcf

我们正在使用WCF构建一个简单的Web服务,我们的产品用它来通过WAN链接上传大文件.它应该是一个简单的HTTP PUT,它在大多数情况下工作正常.

这是服务合同的简化版本:

[ServiceContract, XmlSerializerFormat]
public interface IReplicationWebService
{
    [OperationContract]
    [WebInvoke(Method = "PUT", UriTemplate = "agents/{sourceName}/epoch/{guid}/{number}/{type}")]
    ReplayResult PutEpochFile(string sourceName, string guid, string number, string type, Stream stream);
}
Run Code Online (Sandbox Code Playgroud)

在执行此合同时,我们从中读取数据stream并将其写入文件.这很好用,所以我们在没有足够的磁盘空间来存储文件的情况下添加了一些错误处理.这大致是它的样子:

    public ReplayResult PutEpochFile(string sourceName, string guid, string number, string type, Stream inStream)
    {
        //Stuff snipped
        try
        {
            //Read from the stream and write to the file
        }
        catch (IOException ioe)
        {
            //IOException may mean no disk space
            try
            {
                inStream.Close();
            }
            // if instream caused the IOException, close may throw
            catch
            {
            }
            _logger.Debug(ioe.ToString());
            throw new FaultException<IOException>(ioe, new FaultReason(ioe.Message), new FaultCode("IO"));
        }
    }
Run Code Online (Sandbox Code Playgroud)

为了测试这一点,我将100GB文件发送到没有足够空间容纳文件的服务器.正如预期的那样抛出一个异常,但呼叫inStream.Close()似乎挂了.我检查了它,实际发生的是调用Close()通过WCF管道直到它到达System.ServiceModel.Channels.DrainOnCloseStream.Close(),根据Reflector分配一个Byte[]缓冲区并继续读取流直到它在EOF.

换句话说,Close调用是在返回之前从流中读取整个100GB的测试数据!

现在可能是我不需要调用Close()此流.如果是这样的话,我想解释为什么.但更重要的是,如果有人能够向我解释为什么Close()这样做,为什么它不被视为错误,以及如何重新配置​​WCF以便不会发生,我会很感激.

mar*_*c_s 4

.Close()旨在成为一种“安全”和“友好”的停止操作的方式 - 并且它确实会在关闭之前完成当前正在运行的请求 - 通过设计。

如果您想扔下大锤,请.Abort()改为在客户端代理(或服务主机)上使用。这只是关闭所有内容而不进行检查,也没有很好地等待操作完成。