- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 WCF 下载一个很长的文件。它是一个基于 net-tcp 绑定(bind)的自托管服务。在客户端上,我正在读取流并将其写入后台线程中的磁盘。在 UI 上,有一个取消按钮。我使用 CancellationToken
取消读写循环。
问题是,
如果流是过早的(不是 EOF),那么处理它需要很长时间。
在服务器(c#):
IO.Stream getFile(string filePath) {
return new IO.FileStream(filePath);
}
在客户端(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
当CancellationToken
抛出OperationCancelledException
时,所有三个using block 都会尝试释放它们的资源。现在,当第二个 using block 尝试处置 MessageBodyStream
时,它会挂起 10 分钟。但如果流被完全读取,那么它会很快退出。
我怀疑,这与 10 分钟的 ReceiveTimeout
有关。所以我把它改为30秒和中提琴!现在处理需要 30 秒。
还有一件事。 Dispose
操作实际上超时了。它吃掉了我的 OperationCancelledException
并产生一个 TimeoutException
说 套接字传输在 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...
我不相信一旦没有完全阅读它就无法取消流。另一方面,我不能只是忘记流并让它离开而不进行处理。它必须是一个阻塞等待直到安全释放的调用。
有人可以帮我吗?
堆栈跟踪显示:
' this is interesting
at System.Xml.XmlBinaryReader.Close() ' VVVVVVVVVVVVV
at System.ServiceModel.Dispatcher.StreamFormatter.MessageBodyStream.Close()
at System.IO.Stream.Dispose()
所以我将 using block 更改为 try-finally
block 。我在那里放置了 wcfStrm.close
,然后放置了 wcfStrm.Dispose
。令我惊讶的是,关闭语句很快就过去了,而处理却超时了。现在,如果内部处置真正的罪魁祸首是 Close
那么为什么显式关闭没有挂起?然后即使流关闭,处置也会挂起?
最佳答案
澄清一下,Stream.Dispose()
的实现是调用 Stream.Close()
。 Stream.Close()
的基本实现是调用 Stream.Dispose(bool)
。它与通常如何实现 IDisposable
的准则相反,因此值得注意。
实现 MessageBodyStream.Close()
方法首先关闭正在读取的 Message
,然后关闭与流关联的 XmlDictionaryReader
.
查看完整的堆栈跟踪,问题似乎是该读取器最终调用 SingletonConnectionReader.Close(TimeSpan)
。这将 TimeSpan
作为超时,这是替换 OperationCancelledException
的 TimeoutException
的来源。
此方法尝试读取流的其余部分以完成关闭操作。我无法解释其背后的原理,但事实就是如此。
<小时/>要解决您的问题,您必须停止使用代理类。尽管是 IDisposable
,但在 using
block 中使用任何 WCF 代理并不安全,因为调用 Dispose()
会调用 Close()
,如果出现异常,那不是你的意思。
在这种情况下,在代理上调用 Abort()
将完全解决问题,因为这就是您的意思:中止操作。
using proxy as new ServiceReference1.TestServer
dim wcfStrm = proxy.getFile("c:\100MB.dat")
try
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 try
catch
proxy.Abort()
end catch
finally
wcfStrm.Dispose()
end finally
end using
我不是 VB 开发人员,所以如果我的语法很糟糕,我深表歉意。
关于.net - 在 WCF 中过早处置 MessageBodyStream,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19227665/
我正在使用 WCF 下载一个很长的文件。它是一个基于 net-tcp 绑定(bind)的自托管服务。在客户端上,我正在读取流并将其写入后台线程中的磁盘。在 UI 上,有一个取消按钮。我使用 Cance
我正在从 WCF 服务返回一个 Stream 并尝试将其转换为 MemoryStream。但是在使用 WCF 服务的 Web 应用程序中,我得到的结果是“MessageBodyStream”,而我期待
我正在从我的 wcf 服务器返回流形式的内存流。当我在客户端检索它并将其投回 MemoryStream 时,出现此错误。 我不明白 MessageBodyStream 是从哪里来的,因为我从未使用过它
我是一名优秀的程序员,十分优秀!