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!