Consuming a Web Service Asynchronously

IOTA^_^    

ASP.NET Developer's JumpStart
By Paul D. Sheriff, Ken Getz
Table of Contents
Chapter 30.  Investigating Web Service Consumers


In the previous section, because you're calling the Web Service method directly, your page must wait for the return value before it can display the results. Most commercial Web sites don't require you to sit and wait until the page has completed its processing before displaying confirmation information.

For example, imagine a site where you register for a conference and request a hotel room for the conference at the same time. The conference site might be calling an XML Web Service provided by the hotel, and calling that Web Service might take measurable time. The conference site can't confirm your hotel room they must have the hotel chain do this for you. Rather than forcing you to wait while the conference site works with the hotel chain to get you a confirmation number, they might simply indicate success on the Web page and then send you an e-mail confirmation once they have the hotel information.

In the previous example, you saw that you were required to wait 10 seconds when you requested the inventory level for a specific product. In a real Web site, you might be more likely to return immediately, with a response on the page, and send some notification later once you had gathered the information you needed. In this example, you'll do just that rather than waiting the 10 seconds, you'll return immediately and write to a text file the results of the method call once you receive the information.

TIP

You might want to modify this example to send e-mail rather than writing to a text file. You can use the System.Web.Mail namespace, and its objects, to send a mail message. Because we can't guarantee that you have an available SMTP mail server, we opted to use a text file instead.


Adding the Method Call

Follow these steps to complete the asynchronous example:

  1. Make sure WebForm1.aspx is open in the page designer.

  2. Double-click btnAsync and add the following procedure call to the btnAsync_Click procedure:

     TestAsync() 
  3. Add the TestAsync procedure, shown in Listing 30.3, to your class.

    Listing 30.3 Add Code to Call the Web Service Method Asynchronously
     Private Sub TestAsync()   Dim ws As New InventoryService.Inventory()   Dim acb As New AsyncCallback(AddressOf HandleCallback)   ws.BeginUnitsInStock( _    CInt(txtProductID.Text), acb, ws)   lblResults.Text = "Thanks for your request. " & _    "Check the text file "WebLog.txt" for the results." End Sub 
  4. Add the procedure shown in Listing 30.4, which the .NET Framework calls once the Web Service method call has completed.

    Listing 30.4 Add This Callback Procedure, to Be Called by the .NET Framework
     Private Sub HandleCallback(ByVal ar As IAsyncResult)   Dim ws As InventoryService.Inventory   Dim intProductID As Integer = CInt(txtProductID.Text)   Dim intResults As Integer   ' Get the Web Service object.   ws = CType(ar.AsyncState, _    InventoryService.Inventory)   ' Call the End... procedure.   intResults = ws.EndUnitsInStock(ar) WriteTextFile(FormatResults(intProductId, intResults)) End Sub Private Sub WriteTextFile(ByVal Value As String)     Dim sw As StreamWriter     If Not File.Exists(Server.MapPath("WebLog.txt")) Then       sw = File.CreateText(Server.MapPath("WebLog.txt"))     End If     sw.Write(Value)     sw.Close()   End Sub 
  5. Press F5 to run the project.

  6. Enter a value into the Product ID text box, click Get Inventory (Async), and wait for the response. The page should post back almost immediately, asking you to check the text file for the results.

  7. Close the Browser window and save your project.

  8. Load the Jumpstart\AsyncConsumer\WebLog.txt file in Notepad and you should see the ProductID and the results written in this file.

What's Going On?

Calling a Web Service asynchronously, not waiting for the results, requires a few more steps and a little more care than calling the method synchronously. In the previous example, you did all the work to call a method asynchronously. What did you actually do?

First of all, it's important to investigate the code in the Web Service proxy class, just as you did when creating the synchronous method call. In the Reference.vb file, you'll find the two methods shown in Listing 30.5 (note that the procedure attributes have been removed and the methods have been reformatted for easier reading).

Listing 30.5 The Proxy Class Contains These Two Methods
 Public Function BeginUnitsInStock( _  ByVal ProductID As Integer, _  ByVal callback As System.AsyncCallback, _  ByVal asyncState As Object) As System.IAsyncResult   Return Me.BeginInvoke("UnitsInStock", _    New Object() {ProductID}, callback, asyncState) End Function Public Function EndUnitsInStock( _  ByVal asyncResult As System.IAsyncResult) As Integer   Dim results() As Object = Me.EndInvoke(asyncResult)   Return CType(results(0), Integer) End Function 

These two procedures (BeginUnitsInStock and EndUnitsInStock) call back to the Web Service method (again, using the URL property of the base class). The BeginUnitsInStock procedure sets up the callback, and you call the EndUnitsInStock procedure when the Web Service method call has completed its work. These two procedures are created for you in the proxy class your job is to call them correctly.

When you create an asynchronous callback, you'll always work through these issues:

  • Creating two procedures. You provide two procedures a "start" procedure (TestAsync, in this example) and an "end" procedure (HandleCallback, in this example). You call your start procedure to call the proxy class's Begin… method (BeginUnitsInStock, in this example). Your start procedure can display a status message on the page and allow the output page to display in the user's browser.

  • Setting up the callback. The start procedure registers a callback to your end procedure. Basically, you pass the address of your end procedure to the .NET Framework, which calls your end procedure when the Web Service has finished its work.

  • Handling the callback. When the Web Service method is complete, the .NET Framework calls your end procedure, which calls the End… method in the proxy class (EndUnitsInStock, in this example). In this case, the end procedure writes information to the WebLog.txt text file, although it could e-mail it as well.

The .NET Framework makes it easy for you to create this callback mechanism. The framework supplies two classes specifically for this purpose:

  • AsyncCallback. Describes the exact procedure signature required by the callback procedure. If you want your end procedure to be called by the .NET Framework when the asynchronous method is complete, it must be of this type.

  • IAsyncResult. Contains information about the state of the asynchronous callback. You'll use this type as the parameter to your callback procedure the procedure that the .NET Framework calls when the asynchronous method call has completed.

INTRODUCING DELEGATES

The AsyncCallback type defines a delegate. You may have heard this term before and wondered what it means. When you create a variable of this type, you can only assign the address of a procedure that meets the delegate's exact signature into the variable. In this case, the AsyncCallback delegate type requires any variable of this type to refer to a procedure that

  • Is a Sub

  • Accepts one parameter of type IAsyncResult

Think of it this way: You register your callback procedure with the .NET Framework. It needs to call your procedure when the Web Service method has completed. If your procedure didn't accept the correct parameters, the call from the .NET Framework would fail. Therefore, the framework needs some way to verify, at compile time, that your callback procedure can "answer the call." That's the point of the Delegate data type: You guarantee, at the time you compile the code, that your procedure meets the needs of any other procedure that calls it.

The "Start" Procedure

The code in TestAsync (your "start" procedure) that sets up the callback looks like this:

 Dim ws As New InventoryService.Inventory() Dim acb As New AsyncCallback(AddressOf HandleCallback) ws.BeginUnitsInStock( _  CInt(txtProductID.Text), acb, ws) 

This code takes these actions:

  • It creates a new instance of the InventoryService.Inventory class, just as your code might if calling the method synchronously.

  • It creates a new instance of the AsyncCallback class, passing the address of your "end" procedure (HandleCallback) to the constructor.

  • It calls the BeginUnitsInStock method, provided by the Web Service proxy class.

The BeginUnitsInStock procedure accepts three parameters: the ID of the product you're investigating, the address of the procedure to be called once the asynchronous method is complete, and an object of your choosing (it can be Nothing, if you like). The .NET Framework passes this object on to you at the other end when you're handling the results of the method call. In this case, the code passes the ws object so that your HandleCallback procedure can work with the same Inventory object, retrieving the inventory for the item you requested.

The "End" Procedure

The HandleCallback procedure (your "end" procedure) includes this code:

 Dim ws As InventoryService.Inventory Dim intProductID As Integer = CInt(txtProductID.Text) Dim intResults As Integer ' Get the Web Service object. ws = CType(ar.AsyncState, _  InventoryService.Inventory) ' Call the End... procedure. intResults = ws.EndUnitsInStock(ar) WriteTextFile(FormatResults(intProductId, intResults)) 

This code takes these actions:

  • It declares a variable as InventoryService.Inventory. This variable will refer to the Web Service object created in your "start" procedure and will allow you to call the EndUnitsInStock method.

  • It declares variables to hold the item and item count:

     Dim ws As InventoryService.Inventory Dim intProductID As Integer = CInt(txtProductID.Text) Dim intResults As Integer 
  • It retrieves a reference to the original Web Service object, created in the "start" procedure. Because you passed the BeginUnitsInStock method a reference to this object as a parameter, the .NET Framework passes this along to your callback procedure in the AsyncState property of the IAsyncResult object. You must cast this property to the correct type (using the CType function):

     ws = CType(ar.AsyncState, _  InventoryService.Inventory) 
  • It calls the EndUnitsInStock method of the Web Service object, which retrieves the return value from the Web Service, cached by the .NET Framework (note that you must pass the IAsyncResult object you received as a parameter to the EndUnitsInStock method):

     intResults = ws.EndUnitsInStock(ar) 
  • It writes the results to the Event Log, using the WebLog.txt file located in your Jumpstart\AsyncConsumer folder.

     WriteTextFile(FormatResults(intProductId, intResults)) 

    IOTA^_^    
    Top


    ASP. NET Developer's JumpStart
    ASP.NET Developers JumpStart
    ISBN: 0672323575
    EAN: 2147483647
    Year: 2002
    Pages: 234

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net