Monday, December 10, 2007

In my last post I talked about the WCF async programming model. On the service side you have to create a custom implementation of IAsyncResult. Fortunately this turns out to be pretty much boilerplate code so here is a general purpose one

class UniversalAsyncResult : IAsyncResult, IDisposable
{
  // To store the callback and state passed
  AsyncCallback callback;
  object state;
 
  // For the implementation of IAsyncResult.AsyncCallback
  volatile ManualResetEvent waithandle;

  // Guard object for thread sync
  object guard = new object();

  // complete flag that is set to true on completion (supports IAsyncResult.IsCompleted)
  volatile bool complete;

  // Store the callback and state passed
  public UniversalAsyncResult(AsyncCallback callback, object state)
  {
    this.callback = callback;
    this.state = state;
  }

  // Called by consumer to set the call object to a completed state
  public void Complete()
  {
    // flag as complete
    complete = true;

    // signal the event object
    if (waithandle != null)
    {
      waithandle.Set();
    }

    // Fire callback to signal the call is complete
    if (callback != null)
    {
      callback(this);
    }
  }

 
#region IAsyncResult Members
  public object AsyncState
  {
    get { return state; }
  }
 
  // Use double check locking for efficient lazy allocation of the event object
  public WaitHandle AsyncWaitHandle
  {
    get
    {
      if (waithandle == null)
      {
        lock (guard)
        {
          if (waithandle == null)
          {
            waithandle = new ManualResetEvent(false);
            // guard against the race condition that the waithandle is
            // allocated during or after complete
            if( complete )
            {
              waithandle.Set();
            }

         
}
        }
      }
      return waithandle;
    }
  }

  public
bool
CompletedSynchronously
  {
    get { return false; }
  }

  public
bool
IsCompleted
  {
    get { return complete; }
  }
  #endregion

  #region
IDisposable Members
  // Clean up the event if it got allocated
  public void Dispose()
  {
    if (waithandle != null)
    {
      waithandle.Close();
    }
  }
  #endregion
}

You create an instance of UniversalAsyncResult passing in an AsyncCallback and state object if available. When you have finished your async processing just call the Complete method on the UniversalAsyncResult object.

Comments welcome

 | 
Monday, December 10, 2007 11:07:29 AM (GMT Standard Time, UTC+00:00)  #    Comments [1]TrackbackTracked by:
"UniversalAsyncResult fixes" (.NET Meanderings) [Trackback]
http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,3db7fe2d-a6f4-4f26-b260-2c... [Pingback]
http://realvideopornoo.com [Pingback]
http://tubepornoss.com [Pingback]