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 asynchronously. 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 ServiceModel 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 /tcv:Version35
The client asynchronous version of the service contract for the Add
operation appears similar to the following code.
[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);
...
}
When the /tcv:Version35
option is specified along with the /async
option, the generated client type implements the event-based asynchronous pattern for calling the service. For information, see Event-based Asynchronous Pattern Overview. To access a service operation asynchronously, the application adds an event handler to the [Operation]Completed
event on the client and then calls the [Operation]Async
method (for example, AddAsync
) as shown in the following sample code.
// Create a client.
CalculatorClient client = new CalculatorClient();
// BeginAdd.
double value1 = 100.00D;
double value2 = 15.99D;
client.AddCompleted += new EventHandler<AddCompletedEventArgs>(AddCallback);
client.AddAsync(value1, value2);
In the sample, the client starts two operations asynchronously: Add
and Subtract
.
When the callback function executes, the client accesses the Result
property on the [Operation]CompletedEventArgs
input parameter to retrieve the result.
static void AddCallback(object sender, AddCompletedEventArgs e)
{
Console.WriteLine("Add Result: {0}", e.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 out 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")]
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.
Note: |
---|
The samples may already be installed on your machine. Check for the following (default) directory before continuing.
<InstallDrive>:\WF_WCF_Samples
If this directory does not exist, go to Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4 to download all Windows Communication Foundation (WCF) and WF samples. This sample is located in the following directory.
<InstallDrive>:\WF_WCF_Samples\WCF\Basic\Contract\Service\Asynchronous
|