Closing Returned Streams in WCF

Streams should always be closed after usage to free the resources behind them. WCF web service functions returning values likes streams are no exception. You should never rely on your client to do this but for some reason many WCF streaming examples overlook this.

To correctly dispose return values WCF provides you with two options:

  • Setting the OperationBehaviorAttribute.AutoDisposeParameters to true
  • Using the OperationCompleted event.

I like to use the event as it gives me more control.

Here is what I think is a correctly implemented GetFile method:

public Stream GetFile(string path) {
   Sream fileStream = null;    

   try   
   {
      fileStream = File.OpenRead(path);
   }
   catch(Exception)
   {
      return null;
   }

   OperationContext clientContext = OperationContext.Current;
clientContext.OperationCompleted += new EventHandler(delegate(object sender, EventArgs args)
   {
      if (fileStream != null)
         fileStream.Dispose();
   });

       return fileStream;
}

The dispose method should not throw an error even if the client has already correctly closed the stream.

More info: http://msdn.microsoft.com/en-us/library/system.servicemodel.operationcontext.operationcompleted.aspx

About these ads

6 thoughts on “Closing Returned Streams in WCF

  1. You mention that OperationBehaviorAttribute.AutoDisposeParameters is another way to correctly clean up the stream. Looking up AutoDisposeParameters, I see it defaults to true. Doesn’t this mean that all WCF services default to cleaning themselves up properly? Or, does the default only come into play if I explicitly put the OperationBehavior attribute on each operation?

    Thanks.

    • You’re right, the default value is true. I must admit I don’t know what the default is if you don’t apply the OperationBehaviorAttribute for a method.

      The main difference between the two options is that the AutoDispose directly applies to all the parameters, if this is not what you want you need set the AutoDispose value to false and handle the disposing manually using events.

  2. Doesn’t WCF call Dispose() on the Stream you’ve returned? I’ve come across a problem where Stream had to be implemented to stream some ‘custom’ data. It implemented Dispose() to chain the clean up code together and that certainly appeared to be invoked once WCF was finished.

    What about how to terminate the stream prematurely from the client end, say for example the user waiting for the file download to complete gets bored and decided to cancel it. Somehow the client has to stop this download. Bizarely if you Dispose() the Stream provided by WCF, it blocks until all of the data has been sent and received.

    Thoughts?

  3. Pingback: Returning Azure BLOB from WCF service as a Stream – Do we need to close it? - Windows Azure Blog

  4. Hey! I Like it.
    Nice little post, but it solved my problem. I spent so many hours to solve this problem. But when I came across your post, It has solved my problem.

    Thanks a lot……………..

    Keep putting such nice tips.

  5. There are many posts that focus exclusively on whether WCF actually does the dispose. People point to IL that is intended to do this. However, the question of when the dispose will be done is often as important as whether. In some cases submitting to the vagaries of dispose scheduling can be a real problem, as it was for me.

    This helped. I had a “file in use” error because I was attempting to use a file for which WCF had been taking a lot of time to dispose the associated stream. A subsequent request from the client caused the attempted use of the file. Once I implemented the exit as described the problem I was encountering went away.

    I still don’t understand why dispose would take so long. I was under the impression that WCF called Dispose directly, as opposed to having GC trigger it.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s