在WCF中过早处理MessageBodyStream

inq*_*ive 6 .net streaming wcf dispose timeout

我正在使用WCF下载一个非常长的文件.它是net-tcp绑定的自托管服务.在客户端上,我正在读取流并将其写入后台线程中的磁盘.在UI上,有一个取消按钮.我用a取消了读写循环CancellationToken.

问题是,

如果Stream过早(不是EOF)那么处理它需要很长时间.

在服务器(c#):

IO.Stream getFile(string filePath) {
    return new IO.FileStream(filePath);
}
Run Code Online (Sandbox Code Playgroud)

在客户端(vb):

using proxy as new ServiceReference1.TestServer
    using wcfStrm = proxy.getFile("c:\100MB.dat")
        using fileStrm = new FileStream("d:\destination\100MB.dat")

            dim buff(256) as new Byte

            while true
                cancellationToken.ThrowIfCancellationRequested

                Dim len = wcfStrm.Read(buff, 0, buff.Length)

                if len > 0 then
                    fileStrm.write(buff, 0, len)
                else
                    exit while
                end if
             end while

         end using      
    end using ' <-------------- this hangs for 10Mins
end using
Run Code Online (Sandbox Code Playgroud)

CancellationToken抛出时OperationCancelledException,所有三个使用块都试图处理它们的资源.现在,当第二个使用块尝试处理时MessageBodyStream,它会挂起10分钟.但如果完全读取流,则会快速退出.

我怀疑,它与ReceiveTimeout10分钟有关.所以我改为30秒和中提琴!处置现在需要30秒.

还有一件事.该Dispose操作实际上超时.它吃了我,OperationCancelledException并产生了一种TimeoutException说法The sockket transfer timed out after 00:00:00... bla bla bla

以下是堆栈跟踪

System.TimeoutException: The socket transfer timed out after 00:00:00. You have exceeded the timeout set on your binding. The time allotted to this operation may have been a portion of a longer timeout.
   at System.ServiceModel.Channels.SocketConnection.SetReadTimeout(TimeSpan timeout, Boolean synchronous, Boolean closing)
   at System.ServiceModel.Channels.SocketConnection.ReadCore(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout, Boolean closing)
   at System.ServiceModel.Channels.SocketConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout)
   at System.ServiceModel.Channels.DelegatingConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout)
   at System.ServiceModel.Channels.PreReadConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout)
   at System.ServiceModel.Channels.SingletonConnectionReader.SingletonInputConnectionStream.ReadCore(Byte[] buffer, Int32 offset, Int32 count)
   at System.ServiceModel.Channels.SingletonConnectionReader.SingletonInputConnectionStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at System.ServiceModel.Channels.MaxMessageSizeStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at System.ServiceModel.Channels.SingletonConnectionReader.Close(TimeSpan timeout)
   at System.ServiceModel.Channels.SingletonConnectionReader.SingletonInputConnectionStream.Close()
   at System.ServiceModel.Channels.DelegatingStream.Close()
   at System.Xml.XmlBufferReader.Close()
   at System.Xml.XmlBaseReader.Close()
   at System.Xml.XmlBinaryReader.Close()
   at System.ServiceModel.Dispatcher.StreamFormatter.MessageBodyStream.Close()
   at System.IO.Stream.Dispose()
   at ...somewhere in my code...
Run Code Online (Sandbox Code Playgroud)

我不相信,如果没有完全阅读它就不能取消流.另一方面,我不能忘记流,并让它走,而不是处置.它必须是一个阻塞等待直到安全释放的呼叫.

有人可以帮帮我吗?

编辑

堆栈跟踪显示:

'                                                         this is interesting
   at System.Xml.XmlBinaryReader.Close() '                    VVVVVVVVVVVVV
   at System.ServiceModel.Dispatcher.StreamFormatter.MessageBodyStream.Close()
   at System.IO.Stream.Dispose()
Run Code Online (Sandbox Code Playgroud)

所以我将使用块更改为try-finally块.我放在wcfStrm.close后面wcfStrm.Dispose.令我惊讶的是,紧密的声明迅速通过,处置时间超时.现在,如果内部处置实际的罪魁祸首是Close为什么明确的关闭没有挂起?然后,即使流被关闭,处置也会被绞死?

fla*_*ayn 0

您可以考虑将大文件分成更小的块(流)。您仍然会有延误,但比您的进场时间要短得多。