This topic covers how a client can access a service operation asynchronously. The service in this topic implements the ICalculator interface. The client can call the operations on this interface asynchronously by using the event-driven asynchronous calling model. (For more information about the event-based asynchronous calling model, see Multithreaded Programming with the Event-based Asynchronous Pattern). For an example that shows how to implement an operation asynchronously in a service, see How to: Implement an Asynchronous Service Operation. For more information about synchronous and asynchronous operations, see Synchronous and Asynchronous Operations.
Procedure
To call WCF service operations asynchronously
-
Run the ServiceModel Metadata Utility Tool (Svcutil.exe) tool with both the /async and the /tcv:Version35 command options together as shown in the following command.
svcutil /n:http://Microsoft.ServiceModel.Samples,Microsoft.ServiceModel.Samples http://localhost:8000/servicemodelsamples/service/mex /a /tcv:Version35
This generates, in addition to the synchronous and standard delegate-based asynchronous operations, a WCF client class that contains:
-
Two <operationName>Async operations for use with the event-based asynchronous calling approach. For example:
Public Overloads Sub AddAsync(ByVal n1 As Double, ByVal n2 As Double)
Me.AddAsync(n1, n2, Nothing)
End Sub
Public Overloads Sub AddAsync(ByVal n1 As Double, ByVal n2 As Double, ByVal userState As Object)
If (Me.onBeginAddDelegate Is Nothing) Then
Me.onBeginAddDelegate = AddressOf Me.OnBeginAdd
End If
If (Me.onEndAddDelegate Is Nothing) Then
Me.onEndAddDelegate = AddressOf Me.OnEndAdd
End If
If (Me.onAddCompletedDelegate Is Nothing) Then
Me.onAddCompletedDelegate = AddressOf Me.OnAddCompleted
End If
MyBase.InvokeAsync(Me.onBeginAddDelegate, New Object() {n1, n2}, Me.onEndAddDelegate, Me.onAddCompletedDelegate, userState)
End Sub
public void AddAsync(double n1, double n2)
{
this.AddAsync(n1, n2, null);
}
public void AddAsync(double n1, double n2, object userState)
{
if ((this.onBeginAddDelegate == null))
{
this.onBeginAddDelegate = new BeginOperationDelegate(this.OnBeginAdd);
}
if ((this.onEndAddDelegate == null))
{
this.onEndAddDelegate = new EndOperationDelegate(this.OnEndAdd);
}
if ((this.onAddCompletedDelegate == null))
{
this.onAddCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnAddCompleted);
}
base.InvokeAsync(this.onBeginAddDelegate, new object[] {
n1,
n2}, this.onEndAddDelegate, this.onAddCompletedDelegate, userState);
}
-
Operation completed events of the form <operationName>Completed for use with the event-based asynchronous calling approach. For example:
Public Event AddCompleted As System.EventHandler(Of AddCompletedEventArgs)
public event System.EventHandler<AddCompletedEventArgs> AddCompleted;
-
System.EventArgs types for each operation (of the form <operationName>CompletedEventArgs) for use with the event-based asynchronous calling approach. For example:
<System.Diagnostics.DebuggerStepThroughAttribute(), _
System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")> _
Partial Public Class AddCompletedEventArgs
Inherits System.ComponentModel.AsyncCompletedEventArgs
Private results() As Object
Public Sub New(ByVal results() As Object, ByVal exception As System.Exception, ByVal cancelled As Boolean, ByVal userState As Object)
MyBase.New(exception, cancelled, userState)
Me.results = results
End Sub
Public ReadOnly Property Result() As Double
Get
MyBase.RaiseExceptionIfNecessary
Return CType(Me.results(0),Double)
End Get
End Property
End Class
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class AddCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
{
private object[] results;
public AddCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :
base(exception, cancelled, userState)
{ this.results = results; }
public double Result
{
get {
base.RaiseExceptionIfNecessary();
return ((double)(this.results[0]));
}
}
}
-
In the calling application, create a callback method to be called when the asynchronous operation is complete, as shown in the following sample code.
' Asynchronous callbacks for displaying results.
Private Shared Sub AddCallback(ByVal sender As Object, ByVal e As AddCompletedEventArgs)
Console.WriteLine("Add Result: {0}", e.Result)
End Sub
// Asynchronous callbacks for displaying results.
static void AddCallback(object sender, AddCompletedEventArgs e)
{
Console.WriteLine("Add Result: {0}", e.Result);
}
-
Prior to calling the operation, use a new generic System.EventHandler of type <operationName>EventArgs to add the handler method (created in the preceding step) to the <operationName>Completed event. Then call the <operationName>Async method. For example:
' AddAsync
Dim value1 As Double = 100
Dim value2 As Double = 15.99
AddHandler client.AddCompleted, AddressOf AddCallback
client.AddAsync(value1, value2)
Console.WriteLine("Add({0},{1})", value1, value2)
// AddAsync
double value1 = 100.00D;
double value2 = 15.99D;
client.AddCompleted += new EventHandler<AddCompletedEventArgs>(AddCallback);
client.AddAsync(value1, value2);
Console.WriteLine("Add({0},{1})", value1, value2);
Example
Note: |
|---|
|
The design guidelines for the event-based asynchronous model state that if more than one value is returned, one value is returned as the Result property and the others are returned as properties on the EventArgs object. One result of this is that if a client imports metadata using the event-based asynchronous command options and the operation returns more than one value, the default EventArgs object returns one value as the Result property and the remainder are properties of the EventArgs object.If you want to receive the message object as the Result property and have the returned values as properties on that object, use the /messageContract command option. This generates a signature that returns the response message as the Result property on the EventArgs object. All internal return values are then properties of the response message object.
|
Imports System
Namespace Microsoft.ServiceModel.Samples
' The service contract is defined in generatedClient.vb, generated from the service by the svcutil tool.
Class Client
Public Shared Sub Main()
Console.WriteLine("Press <ENTER> to terminate client once the output is displayed.")
Console.WriteLine()
' Create a client
Dim client As New CalculatorClient()
' AddAsync
Dim value1 As Double = 100
Dim value2 As Double = 15.99
AddHandler client.AddCompleted, AddressOf AddCallback
client.AddAsync(value1, value2)
Console.WriteLine("Add({0},{1})", value1, value2)
' SubtractAsync
value1 = 145
value2 = 76.54
AddHandler client.SubtractCompleted, AddressOf SubtractCallback
client.SubtractAsync(value1, value2)
Console.WriteLine("Subtract({0},{1})", value1, value2)
' Multiply
value1 = 9
value2 = 81.25
Dim result As Double = client.Multiply(value1, value2)
Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result)
' Divide
value1 = 22
value2 = 7
result = client.Divide(value1, value2)
Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result)
Console.ReadLine()
'Closing the client gracefully closes the connection and cleans up resources
client.Close()
End Sub
' Asynchronous callbacks for displaying results.
Private Shared Sub AddCallback(ByVal sender As Object, ByVal e As AddCompletedEventArgs)
Console.WriteLine("Add Result: {0}", e.Result)
End Sub
Private Shared Sub SubtractCallback(ByVal sender As Object, ByVal e As SubtractCompletedEventArgs)
Console.WriteLine("Subtract Result: {0}", e.Result)
End Sub
End Class
End Namespace
using System;
namespace Microsoft.ServiceModel.Samples
{
// The service contract is defined in generatedClient.cs, generated from the service by the svcutil tool.
class Client
{
static void Main()
{
Console.WriteLine("Press <ENTER> to terminate client once the output is displayed.");
Console.WriteLine();
// Create a client
CalculatorClient client = new CalculatorClient();
// AddAsync
double value1 = 100.00D;
double value2 = 15.99D;
client.AddCompleted += new EventHandler<AddCompletedEventArgs>(AddCallback);
client.AddAsync(value1, value2);
Console.WriteLine("Add({0},{1})", value1, value2);
// SubtractAsync
value1 = 145.00D;
value2 = 76.54D;
client.SubtractCompleted += new EventHandler<SubtractCompletedEventArgs>(SubtractCallback);
client.SubtractAsync(value1, value2);
Console.WriteLine("Subtract({0},{1})", value1, value2);
// Multiply
value1 = 9.00D;
value2 = 81.25D;
double result = client.Multiply(value1, value2);
Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);
// Divide
value1 = 22.00D;
value2 = 7.00D;
result = client.Divide(value1, value2);
Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);
Console.ReadLine();
//Closing the client gracefully closes the connection and cleans up resources
client.Close();
}
// Asynchronous callbacks for displaying results.
static void AddCallback(object sender, AddCompletedEventArgs e)
{
Console.WriteLine("Add Result: {0}", e.Result);
}
static void SubtractCallback(object sender, SubtractCompletedEventArgs e)
{
Console.WriteLine("Subtract Result: {0}", e.Result);
}
}
}
See Also
>
© 2007 Microsoft Corporation. All rights reserved.
Last Published: 2009-12-09