Dan Rigsby - Coding Up Style

.Net, C#, & Wcf Development

Async Operations in Wcf: IAsyncResult Model (Server-Side)

Posted by Dan Rigsby on March 26th, 2008

Async Operations in Wcf Series:
Part 1: Event Based Model
Part 2: IAsyncResult Model (Client-Side)
Part 3: IAsyncResult Model (Server-Side)
Part 4: Canceling Operations

This is the third in a four part series on asynchronous operations in Wcf.  If you are new to this series, you might want to read the first section of part one to get an introduction to this post: http://www.danrigsby.com/blog/index.php/2008/03/18/async-operations-in-wcf-event-based-model/

What is the IAsyncResult Model (Server-Side)

The IAsyncResult Model (Server-Side) basically allows you to send a request to the server and the server will callback when the result is ready.  Inside the “callback” method you can send another request to get the actual result.   It is important to note though that this callback method will be invoked on a thread from the server.  So, if you are working with UI code you will need to check if InvokeRequired and Invoke the operation on the UI thread (there is an example of this below).

The IAsyncResult Model (Server-Side) in Wcf is what I call “server-side asynchronous”.  This means that the operations to the server are done completely asynchronously.  The IAsyncResult Model can work as “client-side asynchronous” which was discussed in the previous article: IAsyncResult Model (Client-Side).

There are a few benefits for using “server-side asynchronous” model over a “client-side asynchronous”:

  1. The client doesn’t have to create extra threads.  The can limit programming confusion and help conserve resources on the client.
  2. Opens the door for operations such as canceling an operation or getting the status of a pending operation.  If a “client-side asynchronous” model is used, the operation to the server is done synchronously so there is no way to perform these operation.
  3. Allows the use of both ChannelFactory<> and ClientBase<>  to connect to the server.  In the “client-side asynchronous” model only a ClientBase<> can be used.

How to implement it

AsyncResult Class

The patterns works off of the standard IAsyncResult interface.  You could use the System.Runtime.Remoting.Messaging.AsyncResult, but many times you will want your own implementation of IAsyncResult.  I use a custom AsyncResult base class and inherit from it to add in properties and methods needed by the operations. Here is a base AsyncResult class that you can use:

using System;
using System.Threading;

namespace Rigsby.AsyncOperation
{
    /// <summary>
    /// The result of an asynchronous operation.
    /// </summary>
    public class AsyncResult : IAsyncResult, IDisposable
    {
        private AsyncCallback m_AsyncCallback;
        private object m_State;
        private ManualResetEvent m_ManualResetEvent;

        /// <summary>
        /// Initializes a new instance of the <see cref=”AsyncResult”/> class.
        /// </summary>
        /// <param name=”callback”>The callback.</param>
        /// <param name=”state”>The state.</param>
        public AsyncResult(
            AsyncCallback callback,
            object state)
        {
            this.m_AsyncCallback = callback;
            this.m_State = state;
            this.m_ManualResetEvent = new ManualResetEvent(false);
        }

        /// <summary>
        /// Completes this instance.
        /// </summary>
        public virtual void OnCompleted()
        {
            m_ManualResetEvent.Set();
            if (m_AsyncCallback != null)
            {
                m_AsyncCallback(this);
            }
        }

        #region IAsyncResult Members
        /// <summary>
        /// Gets a user-defined object that qualifies or contains information about an asynchronous operation.
        /// </summary>
        /// <value></value>
        /// <returns>A user-defined object that qualifies or contains information about an asynchronous operation.</returns>
        public object AsyncState
        {
            get
            {
                return m_State;
            }
        }

        /// <summary>
        /// Gets a <see cref=”T:System.Threading.WaitHandle”/> that is used to wait for an asynchronous operation to complete.
        /// </summary>
        /// <value></value>
        /// <returns>A <see cref=”T:System.Threading.WaitHandle”/> that is used to wait for an asynchronous operation to complete.</returns>
        public System.Threading.WaitHandle AsyncWaitHandle
        {
            get
            {
                return m_ManualResetEvent;
            }
        }

        /// <summary>
        /// Gets an indication of whether the asynchronous operation completed synchronously.
        /// </summary>
        /// <value></value>
        /// <returns>true if the asynchronous operation completed synchronously; otherwise, false.</returns>
        public bool CompletedSynchronously
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Gets an indication whether the asynchronous operation has completed.
        /// </summary>
        /// <value></value>
        /// <returns>true if the operation is complete; otherwise, false.</returns>
        public bool IsCompleted
        {
            get
            {
                return m_ManualResetEvent.WaitOne(0, false);
            }
        }
        #endregion IAsyncResult Members

        #region IDisposable Members
        private bool m_IsDisposed = false;
        private event System.EventHandler m_Disposed;

        /// <summary>
        /// Gets a value indicating whether this instance is disposed.
        /// </summary>
        /// <value>
        ///     <c>true</c> if this instance is disposed; otherwise, <c>false</c>.
        /// </value>
        [System.ComponentModel.Browsable(false)]
        public bool IsDisposed
        {
            get
            {
                return m_IsDisposed;
            }
        }

        /// <summary>
        /// Occurs when this instance is disposed.
        /// </summary>
        public event System.EventHandler Disposed
        {
            add
            {
                m_Disposed += value;
            }
            remove
            {
                m_Disposed -= value;
            }
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        public void Dispose()
        {
            if (!m_IsDisposed)
            {
                this.Dispose(true);
                System.GC.SuppressFinalize(this);
            }
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name=”disposing”><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            try
            {
                if (disposing)
                {
                    m_ManualResentEvent.Close();
                    m_ManualResentEvent = null;
                    m_State = null;
                    m_AsyncCallback = null;

                    System.EventHandler handler = m_Disposed;
                    if (handler != null)
                    {
                        handler(this, System.EventArgs.Empty);
                        handler = null;
                    }
                }
            }
            finally
            {
                m_IsDisposed = true;
            }
        }

        /// <summary>
        ///    <para>
        ///        Checks if the instance has been disposed of, and if it has, throws an <see cref=”ObjectDisposedException”/>; otherwise, does nothing.
        ///    </para>
        /// </summary>
        /// <exception cref=”System.ObjectDisposedException”>
        ///    The instance has been disposed of.
        ///    </exception>
        ///    <remarks>
        ///    <para>
        ///        Derived classes should call this method at the start of all methods and properties that should not be accessed after a call to <see cref=”Dispose()”/>.
        ///    </para>
        /// </remarks>
        protected void CheckDisposed()
        {
            if (m_IsDisposed)
            {
                string typeName = GetType().FullName;

                // TODO: You might want to move the message string into a resource file
                throw new System.ObjectDisposedException(
                    typeName,
                    String.Format(System.Globalization.CultureInfo.InvariantCulture,
                        “Cannot access a disposed {0}.”,
                        typeName));
            }
        }
        #endregion IDisposable Members
    }
}
Continuing with our square root service from the previous articles, we will want to extend this base AyncResult class to hold both the input and output values for our operation.  You could have multiple input values such as two numbers you want to add.  In which case you could either have two input values stored in this class or create a “container” class that stores both of the numbers you wish to add.  Since our example has only one input value, our AsyncResult object for determining a square root could look like this:
 
public class GetSquareRootAsyncResult : AsyncResult
{
    private double m_Value;
    private double m_Result;

    public double Value
    {
        get { return m_Value; }
        set { m_Value = value; }
    }

    public double Result
    {
        get { return m_Result; }
        set { m_Result = value; }
    }

    public GetSquareRootAsyncResult(
        AsyncCallback callback,
        object state) : base (callback, state)
    {
    }
}

Contract

For our service contract, we have the GetSquareRoot method which will act as our synchronous version of the operation.  There are 2 new methods here called BeginGetSquareRoot and EndGetSquareRoot.  You must prefix these methods with “Begin” and “End”.  The “Begin” method must return IAsyncResult and the last two parameters must be an AsyncCallback and an object that represents the state.  The “End” method must have a single parameter for the IAsyncResult.  The return value of the “End” method represents the actual result of the operation.  Notice that only the “Begin” version of the the method is decorated with the OperationContract attribute and not the “End” method.  This is important for how these operations are wired up.  As long as you have “AsyncPattern=true” on the “Begin” method’s OperationContract attribute, the service and client will know to look for a corresponding “End” method.

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    double GetSquareRoot(double value);

    [OperationContract(AsyncPattern=true)]
    IAsyncResult BeginGetSquareRoot(double value, AsyncCallback callback, object state);

    double EndGetSquareRoot(IAsyncResult asyncResult);
}

Service

Our service is basically a bare bones implementation of the contract.  The GetSquareRoot method is our synchronous operation and implements a 4 second thread sleep command to simulate the operation taking longer than what it really does.  This will be important when testing the asynchronous vs. the synchronous versions of the method.  Otherwise both methods would return in less than a second.

The BeingGetSquareRoot method creates a new instance of our GetSquareRootAsyncResult class and populates it with the value that we want to get the square root of.  The operation is then pushed into the threadpool and the IAsyncResult is returned from the method.  Once in the threadpool, the operation will be processed when the next thread is available by the Callback method.  The Callback method, executes the operation and calls the OnCompleted method on the GetSquareRootAsyncResult object which in turn signals the callback method on the client.

The EndGetSquareRoot method is will be called by callback method on the client to retrieve the value stored on the server after the client has been signaled.  This method basically just casts the IAsyncResult object passed to it as the GetSquareRootAsyncResult type and returns the value.  You might be asking yourself why the client can’t just do that itself.  The reason is that the IAsyncResult object passed to the client isn’t the actual object on the server, but basically a reference pointer that is passed to the client that the client can send back to the server to identity the object in the server’s memory. (The IAsyncResult returned to the client is of type System.ServiceModel.Channels.ServiceChannel.SendAsyncResult, but you wont find much about this class on msdn or anywhere else on the web.)

Here is an example of a service written against our contract for the GetSquareRoot service:

[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)]
public class MyService : IMyService
{
    #region IMyService Members
    public double GetSquareRoot(double value)
    {
        Thread.Sleep(4000); // Wait 4 seconds
        return Math.Sqrt(value);
    }

    public IAsyncResult BeginGetSquareRoot(double value, AsyncCallback callback, object state)
    {
        GetSquareRootAsyncResult asyncResult =
            new GetSquareRootAsyncResult(callback, state);
        asyncResult.Value = value;

        ThreadPool.QueueUserWorkItem(
            new WaitCallback((Callback)),
            asyncResult);

        return asyncResult;
    }

    public double EndGetSquareRoot(IAsyncResult asyncResult)
    {
        double result = 0;

        using (GetSquareRootAsyncResult getSquareRootAsyncResult =
            asyncResult as GetSquareRootAsyncResult)
        {
            getSquareRootAsyncResult.AsyncWaitHandle.WaitOne();
            result = getSquareRootAsyncResult.Result;
        }

        return result;
    }
    #endregion IMyService Members

    private void Callback(object asyncResult)
    {
        GetSquareRootAsyncResult getSquareRootAsyncResult
            = (GetSquareRootAsyncResult)asyncResult;
        try
        {
            getSquareRootAsyncResult.Result =
                GetSquareRoot(getSquareRootAsyncResult.Value);
        }
        finally
        {
            getSquareRootAsyncResult.OnCompleted();
        }
    }
}

Example Client

For our example client, we have a basic windows forms application where the user can enter a value, send it to the server, and the result will be displayed:

SquareRoot

Here is the code behind this page.  The only tricky things here are the callback method that is passed to the BeginGetSquareRoot method and the call to the EndGetSquareRoot method from that callback method.

public partial class Form1 : Form
{
    IMyService m_Client;

    public Form1()
    {
        InitializeComponent();

        ChannelFactory<IMyService> factory =
            new ChannelFactory<IMyService>(“netTcp”);
        factory.Open();
        m_Client = factory.CreateChannel();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        double value = 0;
        Double.TryParse(m_ValueTextBox.Text, out value);

        m_Client.BeginGetSquareRoot(
            value,
            new AsyncCallback(OnEndGetSquareRoot),
            null);

        m_StartButton.Enabled = false;
        m_ResultTextBox.Text = “Loading…”;
    }

    public void OnEndGetSquareRoot(IAsyncResult asyncResult)
    {
        this.Invoke(
            new MethodInvoker(delegate()
            {
                m_ResultTextBox.Text =
                    m_Client.EndGetSquareRoot(asyncResult).ToString();

                m_StartButton.Enabled = true;
            }));
    }
}
 

Notice that in the OnEndGetSquareRoot method, we can invoking the operation using “this.Invoke”.  This ensures that the operation is called on the UI thread since we are updating a UI element.  We know that OnEndGetSquareRoot is called by the signal on the server, so the method is always called by a thread from the server.

You can download a complete sample of the code discussed in this article here: http://www.danrigsby.com/Files/Rigsby.ServerSideIAsyncResultOperation.zip

5 Responses to “Async Operations in Wcf: IAsyncResult Model (Server-Side)”

  1. Dew Drop - March 28, 2008 | Alvin Ashcraft's Morning Dew Says:

    [...] Async Operations in WCF: IAsyncResult Model (Server-Side) (Dan Rigsby) [...]

  2. Dan Rigsby » Async Operations in Wcf: IAsyncResult Model (Client-Side) Says:

    [...] Async Operations in Wcf: IAsyncResult Model (Server-Side) [...]

  3. Dan Rigsby » Async Operations in Wcf: Event Based Model Says:

    [...] Async Operations in Wcf: IAsyncResult Model (Server-Side) [...]

  4. Dan Rigsby » Async Operations in Wcf: Canceling Operations Says:

    [...] Async Operations in Wcf: IAsyncResult Model (Server-Side) [...]

  5. Mike Says:

    How do you handle Faults in a server side async scenario?

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>