none
How to cancel WCF operation that returns Stream? RRS feed

  • Question

  • I am building a custom WCF service that is designed for net.tcp and net.namedpipe bindings. The binding configurations configured to use StreamedResponse. The service exposes few operations that return Stream object. The service returns a custom stream with overriden Read method.

    On the client side a call to the service looks like this:

    using (var stream = client.GetImage("Thumbnail")) {
      int header = s.ReadByte();
      if (header != 5){
         return;
      }
    }
    

    I would expect that client will first read some amount of data from the service to the buffer. But, after the return statement in line #4 it will abort service operation as a result of stream.Dispose(). However this does not happen.

    I have found that a call to Dispose method of the stream returned as a result of the service operation will always try to read the stream till the end. Thus creating unnecessary load on the server.


    Please mark replies as answers if they help

    Monday, May 5, 2014 11:33 AM

Answers

  • Hi Petro,

    If the Opertion is not IsOneWay, client will always get an response. Actually, even it's IsOneWay, client still get the response but chose to ignore the response.

    So say, there is no way to cancelling a call. But you can async the stream operation. Then, cancel the async operation. The Framework contains several paradigms for asynchronous programming but when it comes to WCF, you kinda fall back to How to: Implement an Asynchronous Service Operation. http://msdn.microsoft.com/en-us/library/ms731177%28v=vs.85%29.aspx


    Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question. This can be beneficial to other community members reading the thread.

    Tuesday, May 13, 2014 2:53 PM

All replies

  • Hi Petro,

    I'd like to suggest you to use try-catch blocks to call Dispose() method explicitly before "return;", as far as I know, "return" could not dispose any source for you.The Dispose() occurs inside a "finally" block when you are using "using" statement.

    Best Regards


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Tuesday, May 6, 2014 8:03 AM
    Moderator
  • You might notice that stream is wrapped with using statement. It will guarantee call to dispose on return from its scope.

    Please mark replies as answers if they help

    Tuesday, May 6, 2014 8:38 AM
  • Hi Petro,

    I mean the stream reading progress make no difference whether you call "return" or not. If you want to dispose stream earlier, you can Dispose() method explicitly before "return"(you can also call GC.Collect to forces garbage collection before "return").

    Regards,

    Haixia


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Tuesday, May 6, 2014 9:23 AM
    Moderator
  • There is no problem with calling dispose, there is a problem with what dispose does. The Dispose method will continue reading the stream until the end, instead of immediatelly close connection with service.

    Please mark replies as answers if they help

    Tuesday, May 6, 2014 10:26 AM
  • Hi,

    Dispose method used to dispose the stream, by writing any changes to the backing store and closing the stream to release resources, Dispose method cannot used to close the connnection with service, the calling to Dispose is passive which occurs when all the operations in using statements finish. As I mentioned previously, "return" make no diffrence on the time when stream call Dispose method, it just used to control the programe flow, it cannot control the release of resource.

    To debug the programe, you might find that in the first sentence "var stream = client.GetImage("Thumbnail")", the applicaiton memory increase(the stream buffering should finished before any other operations in the using statement), if the operations latter do not cost many memory, the memory usage will keep stable till call Dispose method.

    Hope this explaination can help you.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Wednesday, May 7, 2014 3:04 AM
    Moderator
  • No it does not. It is not what I am asking for, the question is not about calling to dispose, memory or what so ever.

    The question is about cancelling service operation that returns a stream.

    The concept of streaming assumes that retrieval of results is driven by the client. I.e. the service is not putting a new data on the channel unless client reads from the stream.

    Now, it is reasonable to assume that whenever clientcloses/disposes the stream, the operation will be cancelled.

    But it does not, if you attempt to close the stream on the client side, instead of what I would expect the implementation of Close/Dispose of the client side stream will continue reading data from the service up untill the end. I want to avoid this, and cancel operation.

    I have found a discussion regarding this topic: Cancelling Streams

    However what is proposed regarding Data and Control channels does complicate the design of the service. The topic was written 8 years ago, so I would expect improvements in that area. However it seems, there is no better way of doing that.


    Please mark replies as answers if they help

    Wednesday, May 7, 2014 11:29 AM
  • Hi Petro,

    If the Opertion is not IsOneWay, client will always get an response. Actually, even it's IsOneWay, client still get the response but chose to ignore the response.

    So say, there is no way to cancelling a call. But you can async the stream operation. Then, cancel the async operation. The Framework contains several paradigms for asynchronous programming but when it comes to WCF, you kinda fall back to How to: Implement an Asynchronous Service Operation. http://msdn.microsoft.com/en-us/library/ms731177%28v=vs.85%29.aspx


    Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question. This can be beneficial to other community members reading the thread.

    Tuesday, May 13, 2014 2:53 PM
  • 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.


    Please mark replies as answers if they help

    Tuesday, August 12, 2014 3:03 PM