.net - Premature disposing a MessageBodyStream in WCF -
i using wcf download long file. self hosted service on net-tcp binding. on client reading stream , writing disk in background thread. on ui, there cancel button. cancel read-write loop using cancellationtoken.
problem is,
if stream premature (not eof) takes long dispose it.
at server (c#):
io.stream getfile(string filepath) { return new io.filestream(filepath); } at client (vb):
using proxy new servicereference1.testserver using wcfstrm = proxy.getfile("c:\100mb.dat") using filestrm = new filestream("d:\destination\100mb.dat") dim buff(256) new byte while true cancellationtoken.throwifcancellationrequested dim len = wcfstrm.read(buff, 0, buff.length) if len > 0 filestrm.write(buff, 0, len) else exit while end if end while end using end using ' <-------------- hangs 10mins end using when cancellationtoken throws operationcancelledexception, 3 using blocks try dispose resources. when second using block tries dispose messagebodystream, hangs 10 minutes. if stream read, exits quickly.
i suspected, had receivetimeout of 10 mins. changed 30 seconds , viola! dispose takes 30 seconds.
one more thing. dispose operation timeouts. eats operationcancelledexception , produces timeoutexception saying the sockket transfer timed out after 00:00:00... bla bla bla
following stack trace
system.timeoutexception: socket transfer timed out after 00:00:00. have exceeded timeout set on binding. time allotted operation may have been portion of longer timeout. @ system.servicemodel.channels.socketconnection.setreadtimeout(timespan timeout, boolean synchronous, boolean closing) @ system.servicemodel.channels.socketconnection.readcore(byte[] buffer, int32 offset, int32 size, timespan timeout, boolean closing) @ system.servicemodel.channels.socketconnection.read(byte[] buffer, int32 offset, int32 size, timespan timeout) @ system.servicemodel.channels.delegatingconnection.read(byte[] buffer, int32 offset, int32 size, timespan timeout) @ system.servicemodel.channels.prereadconnection.read(byte[] buffer, int32 offset, int32 size, timespan timeout) @ system.servicemodel.channels.singletonconnectionreader.singletoninputconnectionstream.readcore(byte[] buffer, int32 offset, int32 count) @ system.servicemodel.channels.singletonconnectionreader.singletoninputconnectionstream.read(byte[] buffer, int32 offset, int32 count) @ system.servicemodel.channels.maxmessagesizestream.read(byte[] buffer, int32 offset, int32 count) @ system.servicemodel.channels.singletonconnectionreader.close(timespan timeout) @ system.servicemodel.channels.singletonconnectionreader.singletoninputconnectionstream.close() @ system.servicemodel.channels.delegatingstream.close() @ system.xml.xmlbufferreader.close() @ system.xml.xmlbasereader.close() @ system.xml.xmlbinaryreader.close() @ system.servicemodel.dispatcher.streamformatter.messagebodystream.close() @ system.io.stream.dispose() @ ...somewhere in code... i not convinced once cannot cancel stream without reading it. on other hand cannot forget stream , let go without disposing. has blocking wait-until-safely-released call.
can please me out here?
edit
the stack trace shows:
' interesting @ system.xml.xmlbinaryreader.close() ' vvvvvvvvvvvvv @ system.servicemodel.dispatcher.streamformatter.messagebodystream.close() @ system.io.stream.dispose() so changed using block try-finally block. there put wcfstrm.close followed wcfstrm.dispose. astonishment, close statement passed swiftly , dispose timed out. if inside dispose actual culprit close why did explicit close didnt hang? , again dispose hanged when stream closed?
to clarify, implementation of stream.dispose() call stream.close(). base implementation of stream.close() call stream.dispose(bool). it's counter guidelines of how typically implement idisposable, it's worth noting.
the messagebodystream.close() method implemented first close message being read, close xmldictionaryreader associated stream.
looking @ full stack trace, problem seems reader calls singletonconnectionreader.close(timespan). takes timespan timeout, , source of timeoutexception replacing operationcancelledexception.
this method attempts read rest of stream complete close operation. can't explain rationale behind that, how is.
to fix problem, must stop using proxy class are. despite being idisposable, it's not safe use wcf proxy in using block, because calling dispose() calls close(), , in event of exception, that's not mean.
in case, calling abort() on proxy fix problem completely, because it's mean: abort operation.
using proxy new servicereference1.testserver dim wcfstrm = proxy.getfile("c:\100mb.dat") try using filestrm = new filestream("d:\destination\100mb.dat") dim buff(256) new byte while true cancellationtoken.throwifcancellationrequested dim len = wcfstrm.read(buff, 0, buff.length) if len > 0 filestrm.write(buff, 0, len) else exit while end if end while end using end try catch proxy.abort() end catch wcfstrm.dispose() end end using i'm not vb developer, apologise if syntax terrible.
Comments
Post a Comment