Using new async invocation pattern in ASP.NET Web Services

My colleague Dennis just asked me how you would asynchronously invoke web services (in VB.NET).

The new way

As Dennis already figured out there is a new way to do this in ASP.NET 2.0. In fact, the new way is all over the .NET Framework 2.0 and is referred to as the event-based asynchronous pattern. There are a few important differences with the old way in .NET 1.0 and 1.1. First, let's set up a sample for an ASP.NET web service.

Public Class VentriloService

    Inherits System.Web.Services.WebService

 

  <WebMethod()> _

  Public Function Listen() As Byte()

    Return Nothing

  End Function

 

End Class

There is a single method called listen in the web service. Another project adds a Web Reference to this webservice (or uses wsdl.exe) and will generate code containing the following:

  • The usual proxy class (VentriloService), but with Listen method, ListenAsync overloads, a ListenCompleted event and a CancelAsync method
  • Specialized event arguments for the ListenCompleted event (ListenCompletedEventArgs)
  • A delegate definition for the signature of the ListenCompleted event (ListenCompletedEventHandler)

You can use the asynchronous version of Listen like this:

Imports VentriloLibrary.localhost

 

Public Class VentriloClient

 

  Public Sub StartListening()

    Dim service As New localhost.VentriloService

    AddHandler service.ListenCompleted, AddressOf ListenCompleted

    service.ListenAsync(Guid.NewGuid())

 

    If SomeCondition = True Then

      service.CancelAsync(Nothing)

    End If

  End Sub

 

  Private Sub ListenCompleted(ByVal sender As Object, ByVal e As ListenCompletedEventArgs)

    If Not e.Cancelled Then

      Console.WriteLine("Call with ID {0} finished with result {1}", e.UserState, e.Result)

    End If

  End Sub

End Class

First, look in the StartListening method. It instantiates a proxy object and registers an event handler for the ListenCompleted event. Pretty easy. Next, it starts the async operation by calling ListenAsync. There are two overloads, one of which takes an UserState argument. More on that in a moment.
Once the asynchronous operation completes, the ListenCompleted event is fired and it will trigger all registered event handlers. Before that time you can cancel all pending async operations by calling CancelAsync.

The UserState that you can pass along to ListenAsync can be any object that you find necessary to correlate this call (it runs on a new thread) inside of the event handler. You could potentially start off multiple async calls with the same event handler, that come back in an arbitrary order. The completed calls can be distinguished by the UserState object that you passed along.

If you want to, you can even go the extra VB mile and use WithEvents to skip the AddHandler call:

Public Class VentriloClient

 

  Dim WithEvents service As New localhost.VentriloService

 

  Public Sub StartListening()

    service.ListenAsync(Guid.NewGuid())

  End Sub

 

  Private Sub ListenCompleted(ByVal sender As Object, ByVal e As ListenCompletedEventArgs) Handles service.ListenCompleted

  End Sub

End Class

The old way

Let me also show you the old fashioned way for contrast. Check this code.

Imports VentriloLibrary.localhost

 

Public Class VentriloClient

  Public Sub StartListening()

    Dim service As New VentriloService

    Dim callback As New AsyncCallback(AddressOf ListenCallback)

    Dim asyncResult As IAsyncResult

    asyncResult = service.BeginListen(callback, Guid.NewGuid())

  End Sub

 

  Public Sub ListenCallback(ByVal ar As IAsyncResult)

    Dim service As New VentriloService

    Dim result As Byte() = service.EndListen(ar)

 

    Console.WriteLine("Call with ID {0} finished with result {1}", _

    DirectCast(ar.AsyncState, Guid), result)

  End Sub

End Class

You can clearly see that you are confronted with lots more of the nitty, gritty details of the asynchronous invocation, including the invocation of the EndListen method. Admitted, this could give you a little more control.

Summary

In summary, the event-based asynchronous pattern is

  • New in .NET Framework 2.0
  • Easier to use than the old pattern
  • Better for control over cancellation of async thread
  • Less useful if you want to poll or make a blocking finish call.
  • More intuitive to add multiple handlers (by calling AddHandler or += (for C#) multiple times)

Dutch readers might want to look at my Visual Basic Group article on delegates from way back. 

Comments

# Dennis' Blog said:

I talked to my colleague Alex Thissen recently about the changes in asynchronous invocation of ASP.NET

woensdag 13 december 2006 16:16