Service Contract: Asynchronous
The Asynchronous sample demonstrates how a client can access a service operation asynchronously and how a service can implement its operations asynchronously. This sample is based on the Getting Started Sample that implements a calculator service. Using synchronous or asynchronous invocation is a local decision and does not impact messages sent on the wire. Although the service implements some synchronous operations, the client can access the service operations in an asynchronous manner. Even though the client calls the service synchronously, the service may implement some operations asynchronously.
Note: |
---|
The setup procedure and build instructions for this sample are located at the end of this topic. |
In this sample, the client is a console application (.exe) and the service is self-hosted in a console application (.exe).
The service implements the ICalculator
interface. The client can call the operations on this interface asynchronously, which means that operations like Add
now have a BeginAdd
and EndAdd
.
Note: |
---|
See the .NET Framework documentation for more details on the Asynchronous pattern. |
The client has generated code that supports these asynchronous operations. The client was created by running the Service Metadata Utility Tool (Svcutil.exe) tool with the /a (async) command option, as follows:
svcutil /n:http://Microsoft.ServiceModel.Samples,Microsoft.ServiceModel.Samples https://localhost:8000/servicemodelsamples/service/mex /a
The client asynchronous version of the service contract for the add operation appears similar to the following:
[System.ServiceModel.ServiceContractAttribute(Namespace=
"http://Microsoft.ServiceModel.Samples")]
public interface ICalculator
{
[System.ServiceModel.OperationContractAttribute(
AsyncPattern=true)]
System.IAsyncResult BeginAdd(double n1, double n2,
System.AsyncCallback callback, object asyncState);
double EndAdd(System.IAsyncResult result);
...
}
To access a service operation asynchronously, the client calls Begin[Operation]
(for example, BeginAdd
) and specifies a callback function, as shown in the following sample code:
// Create a client.
CalculatorClient client = new CalculatorClient();
// BeginAdd.
double value1 = 100.00D;
double value2 = 15.99D;
IAsyncResult arAdd =
client.BeginAdd(value1, value2, AddCallback, client);
Console.WriteLine("Add({0},{1})", value1, value2);
In the sample, the client starts two operations asynchronously: Add
and Subtract
.
When the callback function executes, the client calls End<operation>
(for example, EndAdd
) to retrieve the result:
static void AddCallback(IAsyncResult ar)
{
double result = ((CalculatorClient)ar.AsyncState).EndAdd(ar);
Console.WriteLine("Add Result: {0}", result);
}
All asynchronous behavior is local to the client and has no bearing on the way messages are sent from the client, or processed by the service. The typical reason to use this pattern in a user interface (UI) application is to keep the UI thread free for updating the screen. This pattern is also applicable when a service is acting as a client and you want to free up the message processing thread from calls to other services. The next section demonstrates how to make service operations asynchronous.
The service implements the ICalculator
interface as shown in the following code:
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples",
SessionMode=SessionMode.NotAllowed)]
public interface ICalculator
{
[OperationContract]
double Add(double n1, double n2);
[OperationContract]
double Subtract(double n1, double n2);
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginMultiply(double n1, double n2, AsyncCallback callback, object state);
double EndMultiply(IAsyncResult ar);
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginDivide(double n1, double n2, AsyncCallback callback, object state);
double EndDivide(IAsyncResult ar);
}
The first two operations of the contract are invoked synchronously by the Windows Communication Foundation (WCF) runtime. The last two pairs of operations are used to invoke the service asynchronously. This sample sets the AsyncPattern property to true. This property setting in combination with the implementation of the .NET Framework Asynchronous pattern tell the runtime to invoke the operation asynchronously.
The reason to use this pattern in a service implementation is typically to free message processing threads when doing time-consuming input and output operations like accessing the disk, accessing a database, or calling another service. This sample demonstrates how to wrap file input and output operations with an implementation of IAsyncResult. The base class for the implementation of the MathAsyncResult
class can be reused to write your own implementations of IAsyncResult
.
Note: |
---|
This sample uses PerCall and Multiple to prevent the ordering behavior that comes with a sessionful binding. The wsHttpBinding uses a session by default to establish security context. This does not affect the asynchronous nature of message processing on the client or the service, but it emphasizes the timing of responses and allows the client to observe concurrent, instead of serial, callbacks. |
When you run the sample, the requests and responses of the operation are displayed in the client console window. The Add and Subtract requests do not block because they are invoked asynchronously. Then the Multiply and Divide operations block and their results are displayed at the same time as the requests go out. Finally, the results from the Add and Subtract operations are displayed when those results arrive back at the client. A sleep is used in the service's implementation of Add and Subtract to show the asynchronous callbacks on the client.
Add(100,15.99)
Subtract(145,76.54)
Multiply(9,81.25) = 731.25
Divide(22,7) = 3.14285714285714
Add Result: 115.99
Subtract Result: 68.46
Thread Ids are used on the service to demonstrate that synchronous calls, such as Add and Subtract, are handled on a single thread. Asynchronous calls, such as Multiply and Divide, involve more than one thread. The service output looks like the following:
Received Add Synchronously on ThreadID 11: Sleeping for 3 seconds
Asynchronous call: BeginMultiply on ThreadID 12
Received Subtract Synchronously on ThreadID 12: Sleeping for 3 seconds
IO thread for * operation on ThreadID 13
EndMultiply called on ThreadID 14
Asynchronous call: BeginDivide on ThreadID 14
IO thread for / operation on ThreadID 13
EndDivide called on ThreadID 14
Returning Add Result on ThreadID 11
Returning Subtract Result on ThreadID 12
The .NET Framework Asynchronous pattern can be used either on the client, the service, or both. As this sample shows, the two sides are independent.
To set up, build, and run the sample
Ensure that you have performed the One-Time Setup Procedure for the Windows Communication Foundation Samples.
To build the C# or Visual Basic .NET edition of the solution, follow the instructions in Building the Windows Communication Foundation Samples.
To run the sample in a single- or cross-machine configuration, follow the instructions in Running the Windows Communication Foundation Samples.
Send comments about this topic to Microsoft.
© Microsoft Corporation. All rights reserved.