Скачиваний:
64
Добавлен:
15.03.2015
Размер:
4.31 Mб
Скачать

374

Day 16

Dealing with Slow Services

Web Service methods may take a long time to complete, especially if the method performs a complicated operation or must access other slow components. For instance, an airline reservation Web Service may have to wait on a legacy reservation system that takes a few seconds to complete. In this case, the client program may be blocked, waiting for the Web Service method to complete. This blocking behavior could make the client program appear to be frozen to users, and users might get impatient and stop the client program. The solution to this problem is to call Web Service methods asynchronously.

Calling a Web Service method asynchronously means that each method call is

NEW TERM

broken into two steps:

1.The client program generates a request to the Web Service. This request contains all the necessary parameters for the Web Service method. The client sends the request to the Web Service and, rather than wait for a response, performs other tasks, such as displaying a progress bar. When the client makes the request, it also gives the Web Service a reference to a callback method.

2.When the Web Service is finished, it returns the data, and the Web Service proxy invokes the callback method. The callback method can examine the results from the Web Service and process the results. For the airline reservation example, the client program can inform users about the status of their reservation requests.

If the Web Service doesn’t return a result in time, the client can abort the connection and take steps to tell users that the method failed.

.NET has built-in support for asynchronous calling, and Web Services and Web Service proxies use the .NET classes. If you are experienced with asynchronous calling techniques in .NET, the following explanation for Web Services won’t be any different from what you are used to already. If you’ve never implemented a program that uses asynchronous calling, don’t worry; the rest of this section will give you step-by-step instructions.

The following steps outline how to create a program to call Web Service methods asynchronously. The following sections will explain each step in detail.

1.Create a callback method.

2.In the callback, make a call to the EndXXX proxy method, where XXX is the name of the Web method. This method will return the results from the Web Service method.

3.In the method that calls the Web Service, create an AsyncCallback object that wraps the actual callback method.

ANALYSIS

Putting It All Together with Web Services

375

4.Invoke the Web Service method by using the BeginXXX proxy method, where XXX is the name of the Web method.

5.Write code to do other work or wait for the method to complete. You can abort the call at any time.

Let’s see how to carry out each one of these steps. To simplify the task of learning about asynchronous calling, we’ll use a console application as a client in this first example.

However, you can apply the same techniques to any kind of client application. At the end 16 of this section, you’ll create a Web form that uses asynchronous calling.

Of course, we need a Web Service that contains a slow method to see how this process works. Listing 16.6 shows just such an example.

LISTING 16.6 SlowService.asmx.cs: The Code Behind for a Slow Web Service

1:using System;

2:using System.Threading;

3:using System.Web;

4:using System.Web.Services;

6:namespace WebBook

7:{

8:[WebService]

9:public class SlowService : WebService

10:{

11:[WebMethod]

12:public String SlowMethod(int waitSec)

13:{

14:Thread.Sleep(waitSec * 1000);

15:return “The answer is...43.”;

16:}

17:}

18:}

The SlowMethod (Lines 11–16) uses one parameter, waitSec, to determine how many seconds it should wait. This parameter allows you to set exactly how slow

the method will be in a client program, which is useful for experimentation. The SlowMethod returns a string.

Creating a Callback Method

Creating a callback method is the first step to take for the “asynchronous” client. The code in Listing 16.7 shows a sample callback method.

ANALYSIS

376

Day 16

LISTING 16.7 A Sample Callback Method

1:public void MyCallBack(IAsyncResult ar)

2:{

3:try

4:{

5:String result = slowServ.EndSlowMethod(ar);

6:Console.WriteLine(“Callback:Web Service returned: “ + result);

7:}

8:catch(Exception)

9:{

10:Console.WriteLine(“Callback:The call was aborted!”);

11:}

12:}

All callback methods must follow the pattern on Line 1. That is, the callback method can’t return a value, and the method must take one parameter of type

IAsyncResult. The IAsyncResult result object contains the result of the call to the Web method.

Line 5 contains the code to process the result object and extract the return value from the Web method. Notice that Line 5 uses the EndSlowMethod call from the Web proxy. Every Web proxy generated by Visual Studio (or WSDL.exe) contains a method like this.

For each Web Service method, such as ExcellentMethod, there will be an

EndExcellentMethod and BeginExcellentMethod in the Web proxy by default.

The callback method uses a try...catch block (Lines 3–11) in case the asynchronous call is aborted. The next section will explain how to abort asynchronous calls. When a method is aborted, the callback is invoked immediately, and the EndSlowMethod call throws an exception.

Calling the Web Method Asynchronously

Now that the callback is written, you need to create code to call the Web method asynchronously. As you might have guessed, you must use the BeginSlowMethod (or BeginAppropriateMethod) call to do so. Before doing so, you must take some preparatory steps:

1.Create a new AsyncCallback method that contains a reference to the callback you created in the preceding section. For this example, you use the following code line:

AsyncCallback callbackRef = new AsyncCallback(MyCallBack);

2. Call the Web method using a line like the following:

IAsyncResult ar = slowServ.BeginSlowMethod(5, callbackRef, null);

ANALYSIS
NEW TERM

Putting It All Together with Web Services

377

To understand the preceding code line, let’s examine it from right to left. The

ANALYSIS

BeginSlowMethod call takes three parameters:

The value 5 corresponds to the first parameter that the original SlowMethod receives, so this Web method will take at least 5 seconds to complete.

callbackRef is the AsyncCallback object created in the preceding section.

The null parameter is used for extra information. This parameter should always be

null for the current version of .NET.

16

The asynchronous call returns an IAsyncResult object, which you can use to get information about the asynchronous call’s status. Listing 16.8 uses the asynchronous result object to wait on the method.

LISTING 16.8 Partial Code Sample to Wait for an Asynchronous Call by Polling the Result Object

1:Console.WriteLine(“Waiting on the web service...”);

2:int totalWaitTime = 6000; //wait 6 seconds

3://int totalWaitTime = 1000; //Uncomment this line to be impatient

5://replace this with code to do some real work

6:ar.AsyncWaitHandle.WaitOne(totalWaitTime, false);

8:if(ar.IsCompleted)

9:{

10:Console.WriteLine(“The call completed!”);

11:}

12:else

13:{

14:Console.WriteLine(“The call did not complete in time. Aborting...”);

15:slowServ.Abort();

16:}

Line 2 sets the totalWaitTime variable to the total amount of time to wait in milliseconds. Line 6 calls the WaitOne method, which waits for the IAsyncResult object (the object named ar) to become set to a completed state. This is known as waiting for the object to be signaled. The WaitOne method will return as soon

as the asynchronous call is complete or when the timeout period expires, whichever comes first.

Lines 8–16 test whether the method is completed in time by using the IsCompleted property. If the method isn’t completed in time, the code calls the Abort method (Line 15) to stop the asynchronous call immediately.

378

Day 16

Completing the Asynchronous Client

Listing 16.9 contains the complete code for the console application client.

LISTING 16.9 A Client That Calls a Web Service Asynchronously

1:using System;

2:using System.Threading;

4:using Proxy; //The namespace of the automatically generated proxy

5://change this to the namespace for the web proxy you

6://have generated

7:namespace WebBook

8:{

9:public class CallAsynch

10:{

11:public static void Main()

12:{

13:WebServiceCaller obj = new WebServiceCaller();

14:obj.Call();

15:Thread.Sleep(50);

16:}

17:}

18:public class WebServiceCaller

19:{

20:SlowService slowServ;

21:public void MyCallBack(IAsyncResult ar)

22:{

23:try

24:{

25:String result = slowServ.EndSlowMethod(ar);

26:Console.WriteLine(“Callback:Web Service returned: “ + result);

27:}

28:catch(Exception)

29:{

30:Console.WriteLine(“Callback:The call was aborted!”);

31:}

32:}

33:public void Call()

34:{

35:slowServ = new SlowService();

36:AsyncCallback cb = new AsyncCallback(MyCallBack);

37:

38: IAsyncResult ar = slowServ.BeginSlowMethod(5, cb, null);

39:

40:Console.WriteLine(“Waiting on the web service...”);

41:int totalWaitTime = 6000; //wait 6 seconds

42://totalWaitTime = 1000; //Uncomment this line to be impatient

44:ar.AsyncWaitHandle.WaitOne(totalWaitTime, false);

Putting It All Together with Web Services

379

LISTING 16.9

Continued

 

45:

 

 

46:

if(ar.IsCompleted)

 

47:

{

 

48:

Console.WriteLine(“The call completed!”);

 

49:

}

 

50:

else

 

51:

{

16

52:

Console.WriteLine(“The call did not complete in time.” +

53:“ Aborting...”);

54:slowServ.Abort();

55:}

56:}

57:}

58:}

After running this sample, you should see output similar to Figure 16.2.

FIGURE 16.2

Calling a Web Service using an asynchronous client console application.

If you uncomment Line 42, recompile, and then rerun the client, you should see output similar to Figure 16.3.

FIGURE 16.3

An aborted asynchronous call to a Web Service.

ANALYSIS

380

Day 16

The preceding discussion already detailed most of the code in Listing 16.9. However, one line is worth noting. Line 15 contains a Sleep call after the

Call method. This line is optional and was inserted into this sample so that you can see the result from the callback when the asynchronous call is aborted. Without the delay, the program would exit before the callback had a chance to complete. Removing the delay won’t break the example; the program will still complete gracefully.

Listing 16.9 is fine for demonstration purposes, but a console application probably isn’t your first choice for a Web Service client. Let’s use the concepts in Listing 16.9 to create a Web form client for the SlowService Web Service in Listing 16.6. This client will model a request for an airline reservation, using SlowService as the back-end “reservation system.”

The client will work using the following steps:

1.The Web form will display the message Making Reservation..., similar to Figure 16.4.

FIGURE 16.4

A Web form that calls a Web Service asynchronously.

2.In the Page_Load event, the Web form will generate an asynchronous call to the

SlowService Web Service.

3.The Web form will contain HTML code so that the browser will automatically refresh after 5 seconds.

4.The Page_Load event will contain code to detect whether it has been called a twice. If so, it will check for a result. If the asynchronous call is completed, the results will be shown. If not, the Web form will display a Still waiting... message.

Listing 16.10 shows a Web form to call the SlowService Web Service, and Listing 16.11 shows the code behind file that calls a Web Service asynchronously using the four preceding steps.

ANALYSIS

Putting It All Together with Web Services

381

LISTING 16.10 CallSlow.aspx: A Prototype Reservation Page that Calls a Web Service Asynchronously

1: <%@ Page language=”c#” Codebehind=”CallSlow.aspx.cs”

 

2:

Inherits=”WebBook.CallSlow” %>

 

3: <html>

 

 

4: <head>

 

 

5: <meta http-equiv=’refresh’ content=’5’

 

6:

id=”metaTag” runat=”server”></meta>

16

7: </head>

 

8:<body>

9:<font face=”arial”>

10:<h3><asp:Label ID=”Message” runat=”server”/></h3>

11:<div id=”refreshMessage” runat=”server”>

12:If this page does not automatically refresh in 5 seconds,

13:click <a href=”CallSlow.aspx”>here</a>

14:</div>

15:</font>

16:</body>

17:</html>

Lines 5–6 contain a <meta> tag that tells the browser to refresh the current page after 5 seconds. This <meta> tag is defined as a server control so that it can be

disabled by the code behind file after the reservation is completed successfully. Lines 11–14 contain a <div> tag that’s used exactly the same way as the <meta> tag. The <div> tag will be hidden by the code behind file after the reservation is completed.

LISTING 16.11 CallSlow.aspx.cs: The Code Behind File for Listing 16.10

1:using System;

2:using System.Web.UI;

3:using System.Web.UI.WebControls;

4:using System.Web.UI.HtmlControls;

5:using System.Web.Services.Protocols;

7:using SlowProxy; //namespace for the proxy class. This may be

8: //different in your own project

9:namespace WebBook

10:{

11:public class CallSlow : System.Web.UI.Page

12:{

13:protected Label Message;

14:protected HtmlGenericControl refreshMessage;

15:protected HtmlGenericControl metaTag;

16:

17:protected void MyCallBack(IAsyncResult ar)

18:{

19:Session[“Result”] = ar;

20:}

382

Day 16

LISTING 16.11 Continued

21:

22:protected void Call()

23:{

24:Message.Text = “Making Reservation...”;

26:SlowService slowServ= new SlowService();

27:AsyncCallback cb = new AsyncCallback(MyCallBack);

28:slowServ.BeginSlowMethod(4, cb, null);

29:

30:Session[“CalledMethod”] = true;

31:}

32:

33:private void Page_Load(object sender, System.EventArgs e)

34:{

35:if(Session[“CalledMethod”] == null)

36:{

37:Call();

38:}

39:else if (Session[“Result”] == null)

40:{

41:Message.Text = “Still waiting....”;

42:}

43:else

44:{

45:metaTag.Visible = false;

46:refreshMessage.Visible = false;

47:

48:if(Session[“ReservationMade”] == null)

49:{

50:try

51:{

52:SlowService slowServ = new SlowService();

53:IAsyncResult ar = (IAsyncResult) Session[“Result”];

54:String result = slowServ.EndSlowMethod(ar);

55:

56:Message.Text = “Successfully Made Reservation!”;

57:Session[“ReservationMade”] = true;

58:}

59:catch(Exception ex)

60:{

61:Message.Text = ex.Message;

62:}

63:}

64:else

65:{

66:Message.Text = “Your reservation has been made. “ +

67:“Please return to the XYZ page if you would “ +

68:“like to make another.”;

69:}

70: } 71: } 72: } 73: }
ANALYSIS Lines 17–20 contain the custom callback method for the Web form. This callback varies from the console application example because it stores the asynchronous
result object into session state.
Lines 22–31 contain the Call method. This method varies only slightly from the console application example because it stores a flag indicating that the Web method has been called.
Lines 33–71 contain the Page_Load method. This method contains some complexity because it can be called under a number of different circumstances. First, the method checks to see whether the Web Service has been called (Line 35). If not, it invokes the Call method. Next, Page_Load checks to see whether the Web method has returned (Line 39). If not, it displays a Still waiting... message. The last else clause (Lines 43–70) is executed only if the Web method has been called and returned. The method checks to see whether the asynchronous result object has been processed (Line 48). If not, it processes the object and shows a success message (Line 56). If the asynchronous object is processed, Lines 66–68 display a message directing users to another page; this code makes sure that the asynchronous result object isn’t processed twice.
The result of a successful call by the asynchronous client is shown in Figure 16.5.
FIGURE 16.5
Asynchronous Web form client results after a Web method call has completed.
Summary
Continued
LISTING 16.11
Putting It All Together with Web Services

383

16

Today’s lesson showed how to use session state in a Web Service by giving an example that tracked the amount of time a Web Service spent in a method call for a user. Clients that don’t support cookies, such as Windows forms programs and console applications, can have trouble dealing with Web Services that use session state. You saw some techniques for dealing with the issue in the first part of today’s lesson.