为什么 WCF 在 Close() 上读取输入流到 EOF? [英] Why is WCF reading input stream to EOF on Close()?

查看:30
本文介绍了为什么 WCF 在 Close() 上读取输入流到 EOF?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We're using WCF to build a simple web service which our product uses to upload large files over a WAN link. It's supposed to be a simple HTTP PUT, and it's working fine for the most part.

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

Here's a simplified version of the service contract:

[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中读取数据并将其写入文件.这很好用,所以我们为没有足够的磁盘空间来存储文件的情况添加了一些错误处理.大致如下:

In the implementation of this contract, we read data from stream and write it out to a file. This works great, so we added some error handling for cases when there's not enough disk space to store the file. Here's roughly what it looks like:

    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(),根据反射器分配一个 Byte[] 缓冲区并继续从流中读取,直到它处于 EOF.

To test this, I'm sending a 100GB file to a server that doesn't have enough space for the file. As expected this throws an exception, but the call to inStream.Close() appeared to hang. I checked into it, and what's actually happening is that the call to Close() made its way through the WCF plumbing until it reached System.ServiceModel.Channels.DrainOnCloseStream.Close(), which according to Reflector allocates a Byte[] buffer and keeps reading from the stream until it's at EOF.

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

In other words, the Close call is reading the entire 100GB of test data from the stream before returning!

现在我可能不需要在这个流上调用Close().如果是这种情况,我想解释一下原因.但更重要的是,如果有人能向我解释为什么 Close() 会这样,为什么它不被视为错误,以及如何重新配置​​ WCF 以防止这种情况发生,我将不胜感激.

Now it may be that I don't need to call Close() on this stream. If that's the case I'd like an explanation as to why. But more importantly, I'd appreciate it if anyone could explain to me why Close() is behaving this way, why it's not considered a bug, and how to reconfigure WCF so that doesn't happen.

推荐答案

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

.Close() is intended to be a "safe" and "friendly" way of stopping your operation - and it will indeed complete the currently running requests before shutting down - by design.

如果您想放弃大锤,请在您的客户端代理(或服务主机)上使用 .Abort() 代替.这只是关闭了所有内容而无需检查,也无需等待操作完成.

If you want to throw down the sledgehammer, use .Abort() on your client proxy (or service host) instead. That just shuts down everything without checking and without being nice about waiting for operations to complete.

这篇关于为什么 WCF 在 Close() 上读取输入流到 EOF?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆