代码之家  ›  专栏  ›  技术社区  ›  anelson

为什么wcf在close()上将输入流读取到eof?

  •  5
  • anelson  · 技术社区  · 15 年前

    我们正在使用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() ,根据反射镜分配 Byte[] 缓冲并一直从流中读取数据,直到到达EOF为止。

    也就是说, Close 调用正在从流中读取整个100GB的测试数据,然后返回!

    现在可能我不需要打电话 关闭() 在这条小溪上。如果是这样的话,我想解释一下原因。但更重要的是,如果有人能向我解释为什么 关闭() 是这样的行为,为什么它不被认为是一个错误,以及如何重新配置WCF以避免这种情况发生。

    1 回复  |  直到 15 年前
        1
  •  4
  •   marc_s    15 年前

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

    如果你想扔下大锤,用 .Abort() 而是在客户机代理(或服务主机)上。这只是关闭了所有的事情,而没有检查,也没有等待操作完成。