How to: Implement an Asynchronous Web Service Client Using the Callback Technique

This topic is specific to a legacy technology. XML Web services and XML Web service clients should now be created using Windows Communication Foundation.

The callback technique is one way to implement a Web service client to communicate with a Web service method asynchronously, even though the method may be intended for synchronous access. The technique is explained in the topic Communicating with XML Web Services Asynchronously.

This example is based on a Web service class PrimeFactorizer with a method Factorize, for which the Wsdl.exe tool has generated two asynchronous client proxy methods, BeginFactorize and EndFactorize.

To implement the callback technique

  1. Define a callback function that implements the AsyncCallback delegate.

    public static void FactorizeCallback(IAsyncResult ar)
    
    Public Shared Sub FactorizeCallback(ar As IAsyncResult)
    
  2. Instantiate the AsyncCallback delegate.

    AsyncCallback cb = new AsyncCallback(TestCallback.FactorizeCallback);
    
    Dim cb as AsyncCallback 
    cb = new AsyncCallback(AddressOf TestCallback.FactorizeCallback)
    
  3. Call the Begin method, passing the callback function as the second argument and an object providing state (in this example, the client implementation of PrimeFactorizer) as the third argument.

    IAsyncResult ar = pf.BeginFactorize(factorizableNum, cb, pf);
    
    Dim ar As IAsyncResult = pf.BeginFactorize(factorizableNum, _
                                                         cb, pf)
    
  4. Check the IsCompleted property on the IAsyncResult returned by the Begin method. The value is set to true after the client has received a response from the server.

  5. Within the callback function, access the state object. The IAsyncState parameter's AsyncState property has the object passed as the third parameter to the Begin method.

    PrimeFactorizer pf = (PrimeFactorizer) ar.AsyncState;
    
    Dim pf As PrimeFactorizer = ar.AsyncState
    
  6. Within the callback function, call the End method on the state object obtained in the previous step.

    long[] results = pf.EndFactorize(ar);
    
    Dim results() as Long
    results = pf.EndFactorize(ar)
    

Example

using System;
using System.Runtime.Remoting.Messaging;
using MyFactorize;

class TestCallback
 {           
      public static void Main(){
            long factorizableNum = 12345;
            PrimeFactorizer pf = new PrimeFactorizer();

            //Instantiate an AsyncCallback delegate to use as a parameter
            //in the BeginFactorize method.
            AsyncCallback cb = new AsyncCallback(TestCallback.FactorizeCallback);

          // Begin the Async call to Factorize, passing in our
          // AsyncCalback delegate and a reference
          // to our instance of PrimeFactorizer.
            IAsyncResult ar = pf.BeginFactorize(factorizableNum, cb, pf);
            
            // Keep track of the time it takes to complete the async call
            // as the call proceeds.
         int start = DateTime.Now.Second;
         int currentSecond = start;
         while (!ar.IsCompleted){
            if (currentSecond < DateTime.Now.Second) {
                  currentSecond = DateTime.Now.Second;
                  Console.WriteLine("Seconds Elapsed..." + (currentSecond - start).ToString() );
            }
         }
         // Once the call has completed, you need a method to ensure the
         // thread executing this Main function 
         // doesn't complete prior to the call-back function completing.
         Console.Write("Press Enter to quit");
         int quitchar = Console.Read();
      }
      // Set up a call-back function that is invoked by the proxy class
      // when the asynchronous operation completes.
      public static void FactorizeCallback(IAsyncResult ar)
      {
          // You passed in our instance of PrimeFactorizer in the third
          // parameter to BeginFactorize, which is accessible in the
          // AsyncState property.
          PrimeFactorizer pf = (PrimeFactorizer) ar.AsyncState;
          long[] results;

          // Get the completed results.
            results = pf.EndFactorize(ar);
          
          //Output the results.
            Console.Write("12345 factors into: ");
            int j;
            for (j = 0; j<results.Length;j++){
                  if (j == results.Length - 1)
                      Console.WriteLine(results[j]);
                  else 
                      Console.Write(results[j] + ", ");
            }
      }
}
Imports System
Imports System.Runtime.Remoting.Messaging
Imports MyFactorize

Public Class TestCallback
    Public Shared Sub Main()
       Dim factorizableNum As Long = 12345
       Dim pf As PrimeFactorizer = new PrimeFactorizer()

       'Instantiate an AsyncCallback delegate to use as a 
       'parameter
       ' in the BeginFactorize method.
       Dim cb as AsyncCallback 
       cb = new AsyncCallback(AddressOf TestCallback.FactorizeCallback)

     ' Begin the Async call to Factorize, passing in the
     ' AsyncCallback delegate and a reference to our instance
     ' of PrimeFactorizer.
       Dim ar As IAsyncResult = pf.BeginFactorize(factorizableNum, _
                                                     cb, pf)
            
     ' Keep track of the time it takes to complete the async call as
     ' the call proceeds.
       Dim start As Integer = DateTime.Now.Second
       Dim currentSecond As Integer = start
       Do while (ar.IsCompleted = false)
          If (currentSecond < DateTime.Now.Second) Then
                currentSecond = DateTime.Now.Second
                Console.WriteLine("Seconds Elapsed..." + 
                      (currentSecond - start).ToString() )
          End If
       Loop

      ' Once the call has completed, you need a method to ensure the
      ' thread executing this Main function 
      ' doesn't complete prior to the callback function completing.
       Console.Write("Press Enter to quit")
       Dim quitchar As Integer = Console.Read()
    End Sub

    ' Set up the call-back function that is invoked by the proxy 
    ' class when the asynchronous operation completes.
    Public Shared Sub FactorizeCallback(ar As IAsyncResult)
    
       ' You passed in the instance of PrimeFactorizer in the third
       ' parameter to BeginFactorize, which is accessible in the
       ' AsyncState property.
         Dim pf As PrimeFactorizer = ar.AsyncState
         Dim results() as Long

       ' Get the completed results.
         results = pf.EndFactorize(ar)
        
       'Output the results.
         Console.Write("12345 factors into: ")
         Dim j as Integer
         For j = 0 To results.Length - 1
              If  j = (results.Length - 1) Then
                   Console.WriteLine(results(j) )
              Else 
                   Console.Write(results(j).ToString + ", ")
              End If
        Next j         
     End Sub      
End Class

See Also

Tasks

How to: Implement an Asynchronous Web Service Client Using the Wait Technique
How to: Make an Asynchronous Call from a Web Service Client

Concepts

Communicating with XML Web Services Asynchronously
Building XML Web Service Clients

Other Resources

Creating Clients for XML Web Services