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

时间:2009-11-04 20:58:26

标签: wcf streaming

我们正在使用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);
}

在本合同的实施过程中,我们从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"));
        }
    }

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

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

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

1 个答案:

答案 0 :(得分:4)

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

如果您想丢弃大锤,请在您的客户端代理(或服务主机)上使用.Abort()。这只是在没有检查的情况下关闭所有内容,而不是等待操作完成。