Cook Computing

Implementing the IAsyncResult Design Pattern

July 31, 2011 Written by Charles Cook

A while ago Niko Schuessler blogged on How to implement the IAsyncResult design pattern (as part of an interesting series of posts Exploring Asynchronous Design Patterns). I particularly liked one feature of his code:

I've changed the original version so you are required to derive from the AsyncResultNoResult and AsyncResult<TResult> classes to implement the asynchronous operation. I feel it is more intuitive to give the derived classes responsibility for managing the operation. Also, for classes with many different operations, it reduces the amount of code on the main class if you can move it to the AsyncResultNoResult derived class.

For example, a class with async methods can be written like this:

public class SampleWebClient
{
  public IAsyncResult BeginGet(string uri, AsyncCallback asyncCallback,
      object state)
  {
    var result = new SampleAsyncResult(new Uri(uri), asyncCallback, 
      state, this, "get");
    result.Process();
    return result;
  }

  public string EndGet(IAsyncResult result)
  {
    return AsyncResult<string>.End(result, this, "get");
  }
}

With the implementation of the async method in the class implementing IAsyncResult:

class SampleAsyncResult : AsyncResult<string>
{
  Uri _uri;
  WebRequest _webRequest;
  WebResponse _webResponse;
  Stream _responseStream;
  byte[] _buffer = new byte[4096];
  Stream _outputStream;

  public SampleAsyncResult(Uri uri, AsyncCallback asyncCallback, object state, 
    object owner, string id)
    : base(asyncCallback, state, owner, id)
  {
    _uri = uri;
  }

  protected override void ProcessImpl()
  {
    _webRequest = WebRequest.Create(_uri);
    _webRequest.BeginGetResponse(Try(GetResponseCallback), null);
  }

  void GetResponseCallback(IAsyncResult asyncResult)
  {
    _outputStream = new MemoryStream();
    _webResponse = _webRequest.GetResponse();
    _responseStream = _webResponse.GetResponseStream();
    _responseStream.BeginRead(_buffer, 0, _buffer.Length, Try(ReadCallback), null);
  }

  void ReadCallback(IAsyncResult asyncResult)
  {
    int count = _responseStream.EndRead(asyncResult);
    if (count > 0)
      _outputStream.Write(_buffer, 0, count);
    if (count == 0)
    {
      _outputStream.Position = 0;
      SetResult(new StreamReader(_outputStream).ReadToEnd());
      Complete(null, false);
      return;
    }
    _responseStream.BeginRead(_buffer, 0, _buffer.Length, Try(ReadCallback), null);
  }

  protected override void Completing(Exception ex, bool completedSynchronously)
  {
    if (_responseStream != null)
      _responseStream.Close();
    if (_webResponse != null)
      _webResponse.Close();
  }
}

Note that all the state for the sequence of async calls is held within SampleAsyncResult which results in a cleaner and more readable implementation.

I tweaked Niko's code a little. Now the derived class has to implement an abstract method called ProcessImpl. This is called when Process() is called, enabling the base class to handle any exceptions thrown from ProcessImpl(). For the same reason I added a base class method called Try():

protected AsyncCallback Try(Action<IAsyncResult> action)
{
  return a =>
  {
    try { action(a); }
    catch (Exception ex) { Complete(ex); }
  };
}

I've created a repository at GitHub — asyncresult — which contains my version of AsyncResultNoResult and AsyncResult<TResult>, along with the above sample code.