How to abort a stream from WCF service without reading it to end?
Asked Answered
S

3

17

This is a problems I've been investigating in the last week and can't find any solution. Found posts asking the same but never getting an answer, hopefully this will help others as well.

I have a WCF service that returns an object containing a stream inside it. I use basicHttpBinding with streamed transfer and Mtom to send it to the client.

Client calls the WCF service and closes the proxy immediately after it receives the response object.

Next, the client reads the stream it got from the WCF service and writes it to a file on the local disk. All of this works fine.

My problem is when the client wants to abort the operation and stop downloading the data from the WCF service. If I call .close() on the stream, e.g: serverReply.DataStream.Close(); then it blocks and reads the whole stream from the WCF service till its end before continuing. The stream can be quite large and the network is not always fast.

This is very undesirable for both network resource usage, which is basically wasted on data that has no use anymore. And since basicHttpBinding allows only two concurrent TCP connections (by default) to the WCF service server, it blocks other connection attempts until the stream is read till its end.

I could increase the number of concurrent connections, but that would be a bad solution as it would create an opening for trouble.

For example, 20 aborted downloads that are still downloading the data to throw it away. I need to make the transfer stop completely.

On the client, the stream object is just a regular Stream class, so it only has the close method, nothing else.

Calling .close() or .abort() on the proxy object doesn't help, neither does destroying it using .dispose() or any other method. On the server side, I handle the OperationContext.OperationCompleted event, but it is not fired until the data from the stream is read till the end.

So the question is, how do I close/abort the stream without reading it entirely?

Subtractive answered 29/7, 2012 at 14:38 Comment(1)
Suffering same problem whilst sending really large files ... seems like must be missing something really obvious. am probably going to have to implement chunking as a workaround.Edvard
W
1

After investigation I found that the WCF client will keep reading from the stream until closeTimeout ellapsed, then it will abort connection. You might decrease closeTimeout on client to minimize the problem.

NOTE: You should wrap the code that disposes a stream into try/catch block. The stream.Dispose() method will throw TimeoutException which brakes a guideline of not throwing exceptions in Dispose method.

Whaleboat answered 12/8, 2014 at 14:52 Comment(0)
T
0

Have you tried playing around with binding.MaxBufferSize?
Have you tried playing around with your app.config file settings e.g:

<bindings>
  <wsHttpBinding>
    <binding name="default" maxReceivedMessageSize="2147483647"  maxBufferPoolSize="2147483647" 
             closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" >
      <readerQuotas  maxArrayLength="2147483647" maxBytesPerRead="4096" maxNameTableCharCount="16384"
                     maxDepth="64" maxStringContentLength="2147483647" />
    </binding>

  </wsHttpBinding>
</bindings>

I would minimize the timeouts anf buffer lengths and try to abort or close and see what happens.

Thoracoplasty answered 31/7, 2012 at 18:22 Comment(3)
I tried that but it doesn't help. Once the server starts sending the stream it doesn't stop until all of it is received by the client. Closing the proxy doesn't do anything. It's like there's no apparent way to stop the communication. When the client stops reading the stream, I can see tcp window zero going back to the server. And the server periodically sends a window zero probe to see if the client is ready to read again. And of course the client sends back window zero again. This goes on forever until the process is killed.Subtractive
Have you tried reading the stream using just HttpClient Class, and seeing if you could close the stream?Thoracoplasty
How do I do that without calling a WCF service? I've done some more research and it seems that there is no way to close the stream from the client side. I tried a different approach. I created another service, a control service, and tried to close the stream from there (server side). But no luck. Something just doesn't work, it doesn't close or dispose.Subtractive
F
0

I think you are merely receiving the buffer after close. You should set maxBufferSize to a lower value.

You might also wish to restrict the amount of data read on the server by wrapping your stream and overriding read. Use smaller chunks if you have a low bandwidth client and return a corresponding count from the read method to match the amount you actually read. This would restrict the fill rate of the buffer.

My own tests on this subject involved me writing a NeverEndingStream and returning data always. At some point i called close on the client then almost immediately the close was called on the server. This suggests that the buffer was merely emptied because clearly it would never be able to read my stream till the end.

If you still experience issues then i suggest you track the timing of the Read method on your overridden stream. If the currentReadtime - the lastReadTime is > x then you might instead call Close and throw an exception. That will kill it for sure.

Fleer answered 26/2, 2015 at 9:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.