【问题标题】:Why is WCF reading input stream to EOF on Close()?为什么 WCF 在 Close() 上将输入流读取到 EOF?
【发布时间】:2009-11-04 20:58:25
【问题描述】:

我们正在使用 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 以使这种情况不会发生,我将不胜感激。

【问题讨论】:

    标签: wcf streaming


    【解决方案1】:

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

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

    【讨论】:

    • 感谢您的回复。 ServiceHost.Abort() 的问题在于它中止了整个服务,而不仅仅是正在处理的特定调用。如果有某种方法我可以指示 WCF 强制关闭套接字以响应异常,至少这样我就不必在客户端知道出现问题之前等待传输完成。
    • 在不等待客户端完成发送文件的情况下,我想不出任何方法向 HTTP 客户端报告异常,所以我不得不接受一个在一次。我希望避免这种情况,但考虑到我必须使用的 HTTP 实现,我看不到解决方法
    猜你喜欢
    • 2014-12-19
    • 1970-01-01
    • 2017-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-08
    • 2014-05-09
    • 2023-03-21
    相关资源
    最近更新 更多