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.