ServicesResourcesConferencesOur TeamWeblogsAboutContact
   

Buddhike's Weblog

{binary mind}


Releasing streams in message contracts

In a lot of WCF streaming applications it's common to see a message contract like this.


[MessageContract]

public class DownloadFileRequest

{

    [MessageHeader]

    private string filename;

   

    [MessageHeader]

    private int length;

   

    [MessageBodyMember]

    private Stream fileStream;

   

    public DownloadFileRequest()

    {

    }     

}

 

This often brings up the question "How can I release the stream when the streaming is completed?". I just noticed a nice attempt by using a simple polling mechanism in this article http://www.codeproject.com/WCF/WCF_FileTransfer_Progress.asp. But, there is much simpler and elegant way to do this. You simply have to implement IDisposable interface in your message contract and clean up the stream in the Dispose method.


[MessageContract]
public class DownloadFileRequest : IDisposable
{
    [MessageHeader]
    private string filename;
   
    [MessageHeader]
    private int length;
   
    [MessageBodyMember]
    private Stream fileStream;
   
    public DownloadFileRequest()
    {
    }   
   
    public void Dispose()
    {
        if(fileStream != null)
        {
           fileStream.Dispose();
           fileStream = null;
        }
    } 
}


Once the message has been fully streamed the dispatcher runtime will call Dispose in all input/output parameter objects used to construct the message.


In to a little bit of internals like always ;). I looked up where exactly this happens in the reflector.

As far as I can understand this work is done in MessageRpc.DisposeParameterList method.

 

private void DisposeParameterList(object[] parameters)
{
    IDisposable disposable = null;
    if (parameters != null)
    {
        foreach (object obj2 in parameters)
        {
            disposable = obj2 as IDisposable;
            if (disposable != null)
            {
                try
                {
                    disposable.Dispose();
                }
                catch (Exception exception)
                {
                    if (DiagnosticUtility.IsFatal(exception))
                    {
                        throw;
                    }
                    this.channelHandler.HandleError(exception);
                }
            }
        }
    }
}


So obviously if our Message contract implements IDisposable it will be perfectly disposed by this function.


Have fun!

posted on Thursday, September 06, 2007 8:18 PM

Powered by Community Server, by Telligent Systems