Invoking Web Services Asynchronously

One of the benefits of the multithreading model in Visual Basic .NET is the asynchronous invocation capabilities built on top of the threading model. (Refer to Chapter 6 for more information.) Asynchronous behavior is an integral part of .NET, and this capability is extended to XML Web Services. Following the basic concept of asynchronous behavior from Chapter 6, you can use exactly the same technique to invoke a Web Service asynchronously.

The WSDL utility always adds the asynchronous Begin name and End name methods in the proxy class for each Web method (where name is the name of the Web method). Thus, if you want to invoke a Web method asynchronously, all you need to do is define a callback method, pass this method to the Begin name asynchronous proxy for the Web method, and block, or call End name when the Web Service returns. This is precisely how you invoke any method asynchronously in .NET.

To keep the discussion focused we will use the GetCommissionsList Web method referred to in the last section. The wsdl.exe utility generates the BeginGetCommissionsList and EndGetCommissionsList proxy methods for us. All we need to do is call BeginGetCommissionsList and choose a method for blocking or simply responding when the data is ready. (Chapter 6 demonstrated how to poll IAsyncResult , use WaitHandle , and retrieve the results with EndInvoke .) Listing 14.13 invokes GetCommissionsList asynchronously, retrieving the data when the callback method is called and safely binding the result to a Windows Forms control.

Listing 14.13 Invoking a Web Method Asynchronously
 1:  Imports Service = AsynchWebServiceCall.localhost.Service1 2:  Imports Commission = AsynchWebServiceCall.localhost.Commission 3: 4:  Public Class Form1 5:    Inherits System.Windows.Forms.Form 6: 7:  [ Windows Form Designer generated code ] 8:    Private Sub Form1_Load(ByVal sender As Object, _ 9:      ByVal e As System.EventArgs) Handles MyBase.Load 10: 11:     DoAsynchronousCall() 12:   End Sub 13: 14:   Private Instance As Service = New Service() 15:   Private Sub DoAsynchronousCall() 16:     Instance.BeginGetCommissionsList( _ 17:       AddressOf AsynchCallback, Nothing) 18:   End Sub 19: 20:   Private Sub AsynchCallback(ByVal Result As IAsyncResult) 21:     Dim List() As Commission = _ 22:       Instance.EndGetCommissionsList(Result) 23:       If (DataGrid1.InvokeRequired) Then 24:         Invoke(New Binder(AddressOf BindData), New Object() {List}) 25:       End If 26:   End Sub 27: 28:   Private Delegate Sub Binder(ByVal List() As Commission) 29:   Private Sub BindData(ByVal List() As Commission) 30:     DataGrid1.DataSource = List 31:   End Sub 32: 33: End Class 

Lines 1 and 2 shorten up the declaration of the Web Service and the type returned by the Web Service. (I will get back to this concept in a moment.) The Form1_Load event handler simply calls a method that gets things started. The real work begins in DoAsynchronousCall (lines 15 through 18).

Invoking the Web Method Asynchronously

In line 14 I created an instance of the Web Service proxy class. For our purposes this is fundamentally the same as creating an instance of the Web Service itself (the proxy class actually takes care of that for us). DoAsynchronousCall uses the Web Service proxy instance to call the asynchronous Begin method in lines 16 and 17. I passed the address of a callback method that matches the signature of an AsyncCallback delegate; no additional information is passed, as indicated by the second argument, Nothing . When the data is ready, the code inherited by the proxy class calls the AsynchCallback delegate. Lines 21 and 22 invoke the asynchronous End method, obtaining the results from the list.

Line 21 might be a bit confusing, so let's explore that further. Recall that we defined the GetCommissionsList Web method to return a CommissionsDataList object. Well, clients won't know anything about the typed collection. Instead clients will get an array of the collected type. Hence, we declare the return type as an array of Commission objects. You do have the option of implementing or using the typed collection itself if you have access to the original assembly (as we do in this case); however, when you are using third-party Web Services, you will probably not have the supporting assemblies.

Marshaling Data onto the Windows Forms Thread

Finally, InvokeRequired is checked in line 23, and Invoke is called in line 24. InvokeRequired is superfluous; it is really there just as a reminder. The proxy class will invoke the callback on a different thread than the one the Windows Forms controls are on. Since Windows Forms controls are not thread-safe, we need to marshal the data onto the same thread as the one containing the controls. This is the purpose of the Invoke method. We use a custom System.Delegate (I named it Binder ) to define the method we are calling ( BindData ) and call that method by passing the delegate and an array of parameters to the Control.Invoke method. BindData is defined in the form, as shown in Listing 14.13 (lines 29 through 31), so we'll use the form's Invoke method to get the array of Commission objects onto the same thread as the one the data grid is on. Unfortunately, if you miss this last bit of code, your Windows Forms application will likely be unstable and may even crash.

Visual Basic. NET Power Coding
Visual Basic(R) .NET Power Coding
ISBN: 0672324075
EAN: 2147483647
Year: 2005
Pages: 215
Authors: Paul Kimmel © 2008-2017.
If you may any questions please contact us: