Dan Rigsby - Coding Up Style

.Net, C#, & Wcf Development

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

Posted by Dan Rigsby on March 20th, 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
Part 5: Handling Exceptions

This is the second 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 (Client-Side)

The IAsyncResult Model (Client-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 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). You could also look at using the Event Based Model which does come back on the main UI thread, or look at setting up a SynchronizationContext.

The IAsyncResult Model (Client-Side) in Wcf is what I call “client-side asynchronous”.  This means that the operations to the server are still done synchronously, but the client does all of the dirty to work to make it appear asynchronous to the calling method.  The IAsyncResult Model can work as both “client-side asynchronous” and “sever-side asynchronous”, but we will get into the server-side this in the next article.  There are a lot of benefits to a “sever-side asynchronous” model.  If you are considering using the IAsyncResult Model (Client-Side), you might want to at least read over the IAsyncResult Model (Server-Side), to see if the benefits are of value to you.

Here is an example using the IAsyncResult Model (Client-Side) in Wcf:

ServiceReference.MyServiceClient m_Client;

public Form1()
{
    InitializeComponent();

    m_Client = new ServiceReference.MyServiceClient();
    m_Client.BeginGetSquareRoot(value, new AsyncCallback(OnEndGetSquareRoot), null);
}

void OnEndGetSquareRoot(IAsyncResult asyncResult)
{
    this.Invoke(
        new MethodInvoker(delegate()
        {
            MessageBox(m_Client.EndGetSquareRoot(asyncResult).ToString());
        }));
}
 

Notice how the callback method is wrapped in an Invoke statement. This is to ensure that the code in the delegate is executed by the main UI thread.

If this class is firing multiple asynchronous events, you will need some way to know which request the AsyncCallback correlates to.  To achieve this, you can use the “object UserState” parameter populate some unique value such as a Guid.  Then in the returned AsyncCallback, you can check the “asyncResult.AsyncState” to see if it matches the unique value for a particular operation.  You could accomplish this like so:

ServiceReference.MyServiceClient m_Client;
string m_MyOperationId;

public Form1()
{
    InitializeComponent();

    m_Client = new ServiceReference.MyServiceClient();

    m_MyOperationId = Guid.NewGuid().ToString();
    m_Client.BeginGetSquareRoot(value, new AsyncCallback(OnEndGetSquareRoot), m_MyOperationId);
}

void OnEndGetSquareRoot(IAsyncResult asyncResult)
{
    m_ResultTextBox.Invoke(
        new MethodInvoker(delegate()
        {
            if (asyncResult.AsyncState.ToString() == m_MyOperationId)
            {
                MessageBox(m_Client.EndGetSquareRoot(asyncResult).ToString());
            }
        }));
}

How to enable it?

The event based model requires .Net version 3.5 and only works if you are using a generated proxy or some class that derivess from System.ServiceModel.ClientBase.  This approach cannot be used with a client generated through a ChannelFactory, since it relies on the InvokeAsync method in the ClientBase class.  This doesn’t mean you have to use a generated proxy though.  You can still hand code a ClientBase on your own and take advantage of this.  This nice thing about this method is that there is no work to be done on the service side.  So if you are working with an existing service, you don’t have to worry about having to modify the existing code.

To build the proxy you could go through the command line and use svcutil.exe to generate the proxy like so:

svcutil http://localhost:8000/MyService/mex /async

Note you could also use the option “/tcv:Version35:”.  If you add this, then both the IAsyncResult Model and Event Based Model methods will be generated.

Or you could generate the proxy through Visual Studio with the “Add Service Reference” wizard. The first thing you might notice is that this wizard has a lot of new features compared to the Visual Studio 2005 version.  In the first screen, enter the address to the service wsdl, click “Go” to download the wsdl, then click on the “Advanced” button at the bottom of the window for more options:

AddService1

This will bring up an advanced window for “Service Reference Settings”.  Just check the box for “Generate asynchronous operations”.  This will cause the wizard to generate both the IAsyncResult Model and Event Based Model methods into your proxy classes (there is no way to tell it to just generate the IAsyncResult Model methods in .Net 3.5):

AddService2

The generated proxy will contain the following items for use with the IAsyncResult  Model (Client-Side):

  1. BeginMyOperation methods: For every operation, a new method is created whose same name is the operation name with “Begin” prepended at the front. These methods are used to initiate the asynchronous operation.  They always have a return result of “IAsyncResult” and add 2 new parameters at the of the list:
    1. “System.AsyncCallBack callback”: This is the callback method to call when the operation is complete.  The method signature must match the System.AsyncCallBack delegate.
    2. “object asyncState”: An object that represents the state of the asynchronous call.  This object can be used to pass information from the calling method to the callback method.  This could be used to pass a unique identifier for the operation such as a Guid or any other data.
  2. EndMyOperation methods: For every operation, a new method is created whose same name is the operation name with “Begin” prepended at the front. These methods are used to retrieve the actual return result of the operation from within the AsyncCallback method. These methods return the result that would be returned from the original synchronous method and take in the IAsyncResult of the operation results to retrieve.

There are other items added to the proxy code when selecting this option. Some of these are private methods used internally to wire up the IAsyncResult Model operations.  If you are using .Net 3.5, some of these new methods are used for the Event Based Model.

Note that every method in the service gets an Begin and End version when you generate the proxy through SvcUtil or in Visual Studio.  If you only want a select number of asynchronous methods, you could always manually remove the addition methods, or you could manually create your own classes and not rely on the generated proxies.  If you are going to hand code proxies, I recommend that you generate them first, and use that code as an example to build on.

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

7 Responses to “Async Operations in Wcf: IAsyncResult Model (Client-Side)”

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

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

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

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

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

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

  4. Chris Says:

    Hi Dan,

    I’ve been playing around with your code for the client and server side asynch calling and have them working nicely however I’ve increased the sleep time on your service to be greater than 1 minute as I believed the asynch calling would overcome timeouts but both of your examples return timeout errors…

    “The HTTP request to ‘http://localhost:8080/MyService’ has exceeded the allotted timeout of 00:00:59.9780000. The time allotted to this operation may have been a portion of a longer timeout.”

    How do I over come this, am I missing the point of the asynch calling…

  5. Rayman Says:

    You can achive the timeout problem by modifying the web.config (or app.config) on the server side. Here is an example:

  6. Chris Says:

    Ah yes, I discovered this while playing around a little more yesterday…. by setting the sendTimeout I managed to overcome the the error.

    Thanks again

  7. Dan Rigsby » Async Operations in Wcf: Handling Exceptions Says:

    [...] Dan Rigsby on August 28th, 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 Part 5: Handling [...]

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>