Async Operations in Wcf: Event Based Model
Posted by Dan Rigsby on March 18th, 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 first in a four part series on asynchronous operations in Wcf. Asynchronous operations allow for a client to send a request to the server and have the server callback to the client when the operation is complete. This frees up the client to do other things and gets around any message timeout issues.
Wcf applications can achieve asynchronous requests in two ways (as described in Async Programming Design Patterns):
- Event Based Model: Event based asynchronous operations (see Event-based Asynchronous Pattern). This occurs on the client-side only.
- IAsyncResult Model: Asynchronous operations using System.IAsyncResult based object (see IAsyncResult Pattern). This can occur on the client-side or server-side.
This series will cover 4 areas including the Event Based Model, the IAsyncResult Model (client-side), the IAsyncResult Model (server-side), and a fourth article about how you could extend the IAsyncResult Model to support canceling an operation. All of the examples used will be based on a Wcf Service that can be used to get the square root of a number. A synchronous method to do this might be called something like “double GetSquareRoot(double number)”. Our asynchronous methods will build on top of this. Thread.Sleep(4000) is called on this method on the service to make the method wait for 4 seconds. This is necessary because otherwise the service would return the result very quickly, and you wouldn’t be able to really tell that it running asynchronously. In a real production system, the service would be doing something much more time intensive such as a long database query.
In this first article, we will looking at the Event Based Model in depth.
What is the Event Based Model
The Event Based Model basically allows you to subscribe to an event for completed operations and then send the operation to the server. When the operation is complete the method you used to subscribe to the event will be called and you can process the results. It is important to note though that this callback method will be called on the same thread that was used to call the method. This can be good if you are in a windows forms environment and need thing to execute on the main UI thread. However if you want to look thread that called the method you can’t really do this. So if you wanted to look at the calling thread’s culture for instance and maybe format the datetime or number values differently, then you are out of luck. If you need to know what thread called the callback method, you might want to consider using the IAsyncResult Model.
The Event Based Model 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 this in the next article. There are a lot of benefits to a “sever-side asynchronous” model. If you are considering using the Event Based Model, you might want to at least read over the IAsyncResult Based “sever-side asynchronous” Model to see if the benefits are of value to you.
Here is an example using the Event Based Model in Wcf:
ServiceReference.MyServiceClient m_Client;
public Form1()
{
InitializeComponent();
m_Client = new ServiceReference.MyServiceClient();
m_Client.GetSquareRootCompleted +=
new EventHandler<ServiceReference.GetSquareRootCompletedEventArgs>(client_GetSquareRootCompleted);
m_Client.GetSquareRootAsync(value);
}
void client_GetSquareRootCompleted(
object sender,
Rigsby.EventBasedWcfAsyncOperation.ServiceReference.GetSquareRootCompletedEventArgs e)
{
MessageBox.Show(e.Result.ToString());
}
If this class is firing multiple asynchronous events, you will need some way to know which request the EventArgs correlates to. To achieve this, there is a overloaded Async method that takes in an “object UserState”. You can use this to populate some unique value such as a Guid. Then in the returned EventArgs you can check the “e.UserState” 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_Client.GetSquareRootCompleted +=
new EventHandler<ServiceReference.GetSquareRootCompletedEventArgs>(client_GetSquareRootCompleted);
m_MyOperationId = Guid.NewGuid().ToString();
m_Client.GetSquareRootAsync(value, m_MyOperationId);
}
void client_GetSquareRootCompleted(
object sender,
Rigsby.EventBasedWcfAsyncOperation.ServiceReference.GetSquareRootCompletedEventArgs e)
{
if ((string)e.UserState == m_MyOperationId)
{
MessageBox.Show(e.Result.ToString());
}
}
The full Event Based Pattern allows for progress updates and the ability to cancel a running operation. Wcf doesn’t support either of these at this time. We will look at ways to cancel async operations in a later article.
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 /tcv:Version35
Note the option “/tcv:Version35:”. If you don’t add this, then only the IAsyncResult Model methods will be generated.
Or you could generate the proxy through Visual Studio with the “Add Service Reference” wizard. You need to make sure that you project is targeted for “.Net Framework 3.5″, otherwise it will just generate the IAsyncResult Model methods. 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:
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 Event Based Model methods):
The generated proxy will contain the following items for use with the Event Based Model:
- MyOperationCompletedEventArgs: For every operation, an event args class will be created which is used to return arguments from the MyOperationCompletedEvent. These classes derive from System.ComponentModel.AsyncCompletedEventArgs and contain the value that is returned by the operation.
- MyOperationCompleted Event: For every operation, an event is created on the proxy when returns the event args for the operation. Subscribe to this event to get the results of an asynchronous operation that uses the Event Based Model.
- MyOperationAsync methods: For every operation, two new methods (one method is an override of the other) are created which always return void and whose names are the operation name with “Async” appended at the end. These are the actual methods that are used to make the asynchronous calls in the Event Based Model. The result of these methods will be returned via the MyOperationCompleted Event. The first method generated has the same parameters as the original method. The second method generated adds an “object UserState” as the last parameter. This UserState is used to identify the operation or to pass information about the operation.
There are other items added to the proxy code when selecting this option, but those are for the IAsyncResult Model which will be discussed in the next article in this series.
Note that every method in the service gets an Aync 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 and EventArgs, 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.EventBasedWcfAsyncOperation.zip











March 30th, 2008 at 11:09 pm
[...] Async Operations in Wcf: Event Based Model [...]
May 3rd, 2008 at 2:42 am
[...] En kort serie om asynkrona anrop i WCF Filed under: WCF [...]
May 18th, 2008 at 4:33 am
[...] This event based model requires .NET version 3.5. Check out Dan Rigsby’s article for more [...]
August 28th, 2008 at 1:58 pm
[...] by Dan Rigsby on August 27th, 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 [...]