How to: Call Operations Asynchronously Using a Channel Factory
This topic covers how a client can access a service operation asynchronously when using a ChannelFactory-based client application. (When using a System.ServiceModel.ClientBase object to invoke a service you can use the event-driven asynchronous calling model. For more information, see How to: Call WCF Service Operations Asynchronously. For more information about the event-based asynchronous calling model, see Multithreaded Programming with the Event-based Asynchronous Pattern.)
The service in this topic implements the ICalculator
interface. The client can call the operations on this interface asynchronously, which means that operations like Add
are split into two methods, BeginAdd
and EndAdd
, the former of which initiates the call and the latter of which retrieves the result when the operation completes. For an example showing how to implement an operation asynchronously in a service, see How to: Implement an Asynchronous Service Operation. For details 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 the /async option as shown in the following command.
svcutil /n:http://Microsoft.ServiceModel.Samples,Microsoft.ServiceModel.Samples https://localhost:8000/servicemodelsamples/service/mex /a
This generates an asynchronous client version of the service contract for the operation.
Create a callback function to be called when the asynchronous operation is complete, as shown in the following sample code.
Private Shared Sub AddCallback(ByVal ar As IAsyncResult) Dim result = (CType(ar.AsyncState, CalculatorClient)).EndAdd(ar) Console.WriteLine("Add Result: {0}", result) End Sub
static void AddCallback(IAsyncResult ar) { double result = ((CalculatorClient)ar.AsyncState).EndAdd(ar); Console.WriteLine("Add Result: {0}", result); }
To access a service operation asynchronously, create the client and call the
Begin[Operation]
(for example,BeginAdd
) and specify a callback function, as shown in the following sample code.Dim factory As New ChannelFactory(Of ICalculatorChannel)() Dim channelClient As ICalculatorChannel = factory.CreateChannel() ' BeginAdd Dim value1 = 100.0R Dim value2 = 15.99R Dim arAdd As IAsyncResult = channelClient.BeginAdd(value1, value2, AddressOf AddCallback, channelClient) Console.WriteLine("Add({0},{1})", value1, value2)
ChannelFactory<ICalculatorChannel> factory = new ChannelFactory<ICalculatorChannel>(); ICalculatorChannel channelClient = factory.CreateChannel(); // BeginAdd double value1 = 100.00D; double value2 = 15.99D; IAsyncResult arAdd = channelClient.BeginAdd(value1, value2, AddCallback, channelClient); Console.WriteLine("Add({0},{1})", value1, value2);
When the callback function executes, the client calls
End<operation>
(for example,EndAdd
) to retrieve the result.
Example
The service that is used with the client code that is used in the preceding procedure implements the ICalculator
interface as shown in the following code. On the service side, the Add
and Subtract
operations of the contract are invoked synchronously by the Windows Communication Foundation (WCF) run time, even though the preceding client steps are invoked asynchronously on the client. The Multiply
and Divide
operations are used to invoke the service asynchronously on the service side, even if the client invokes them synchronously. This example sets the AsyncPattern property to true. This property setting, in combination with the implementation of the .NET Framework asynchronous pattern, tells the run time to invoke the operation asynchronously.
<ServiceContract(Namespace := "http://Microsoft.ServiceModel.Samples")> _
Public Interface ICalculator
<OperationContract> _
Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double
<OperationContract> _
Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double
'Multiply involves some file I/O so we'll make it Async.
<OperationContract(AsyncPattern := True)> _
Function BeginMultiply(ByVal n1 As Double, ByVal n2 As Double, ByVal callback As AsyncCallback, ByVal state As Object) As IAsyncResult
Function EndMultiply(ByVal ar As IAsyncResult) As Double
'Divide involves some file I/O so we'll make it Async.
<OperationContract(AsyncPattern := True)> _
Function BeginDivide(ByVal n1 As Double, ByVal n2 As Double, ByVal callback As AsyncCallback, ByVal state As Object) As IAsyncResult
Function EndDivide(ByVal ar As IAsyncResult) As Double
End Interface
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
public interface ICalculator
{
[OperationContract]
double Add(double n1, double n2);
[OperationContract]
double Subtract(double n1, double n2);
//Multiply involves some file I/O so we'll make it Async.
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginMultiply(double n1, double n2, AsyncCallback callback, object state);
double EndMultiply(IAsyncResult ar);
//Divide involves some file I/O so we'll make it Async.
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginDivide(double n1, double n2, AsyncCallback callback, object state);
double EndDivide(IAsyncResult ar);
}