Using the WebService Behavior


Using the WebService Behavior

If you're using Internet Explorer (version 5.0 or higher), you can access a Web service directly from the browser. You can access a Web service directly through client script by using the WebService behavior.

A behavior is a component that you can associate with an element within an HTML page that extends the element's default functionality. You already saw some examples of behaviors earlier in this book. In Chapter 8, "Additional Samples and Controls," you learned about the Internet Explorer WebControls , such as the TreeView and Toolbar controls. The client-side functionality of these controls is implemented through Internet Explorer behaviors.

The main advantage of using a behavior to access a Web service is that you can update the content of a page without reloading the whole page. For example, later in this chapter, you learn how to use the WebService behavior to display a continuously updated featured product section in an HTML page. The contents of the featured product section automatically change every five seconds without reloading any other content of the page.

Before you can use the WebService behavior, you need to download the webservice.htc file from the Microsoft MSDN library (msdn.microsoft.com). This file is currently located at the following address:

http://msdn.microsoft.com/downloads/samples/internet/behaviors/library/webservice/default.asp

Examining Limitations of the WebService Behavior

Before you start building pages with the WebService behavior, you should be aware of some of the behavior's limitations.

The first limitation concerns the XML Web services that you can access through the behavior. You can use the WebService behavior to access only those Web services located in the same domain as the Web page that contains the behavior. (This limitation is a direct result of the security restrictions built into DHTML.) If you want to access a remote Web service, you must access it through a proxy Web service located in the same domain.

The second limitation concerns the data types that you can access through the WebService behavior. The WebService behavior supports all the base .NET types, such as Strings , Integers , and DateTimes . The WebService behavior also supports arrays of the base .NET types. For example, you can pass an array of integers through the WebService behavior.

Unfortunately, however, the behavior has no direct support for more complex types, such as DataSets , DataTables , Collections , or custom objects. For example, you can't pass a DataSet through the WebService behavior and bind it to a drop-down list box on the client. Later in this chapter, in the section titled, "Using the WebService Behavior to Retrieve Database Data," you explore one method of getting around this limitation.

Creating a Simple Page with a WebService Behavior

In the preceding chapter, you created a TemperatureService XML Web service that enabled you to convert between degrees Celsius and degrees Fahrenheit. You learned how to build a proxy class to access this Web service through an ASP.NET page. In this section, you learn how to access the TemperatureService Web service directly through the WebService behavior and bypass any need for a proxy class.

The code for the TemperatureService is contained in Listing 23.1.

Listing 23.1 TemperatureService.asmx
 <%@ WebService Class="TemperatureService" %> Imports System Imports System.Web.Services <WebService( Namespace:="http://yourdomain.com/webservices" )> _ Public Class TemperatureService : Inherits WebService   <WebMethod()> Public Function ToCelsius( TF As Double ) As Double     Return ( 5/9 ) * ( TF - 32 )   End Function   <WebMethod()> Public Function ToFahrenheit( TC As Double ) As Double     Return ( 9/5 ) * TC + 32 End Function End Class 

The C# version of this code can be found on the CD-ROM.

To access the TemperatureService Web service with the WebService behavior, you need to complete the following steps:

  1. Attach the WebService behavior to an element within the HTML page.

  2. Provide the location of the XML Web service by invoking the WebService behavior's useService method.

  3. Call a method of the XML Web service by invoking the WebService behavior's callService method.

The page in Listing 23.2 illustrates how to add the WebService behavior to a page and invoke the behavior's methods .

NOTE

Because this is a book on ASP.NET, I named all the pages in this section with the extension .aspx . However, the WebService behavior works equally well in a plain, old HTML page.


Listing 23.2 BehaviorSimple.aspx
 <SCRIPT language="JavaScript"> var intCallID = 0; function Init() {   Service.useService("/webservices/TemperatureService.asmx?WSDL", "TemperatureService"); } function Service_Result() {   lblCelsius.innerText = event.result.value; } function Button_Click() {   intCallID = Service.TemperatureService.callService( "ToCelsius", txtFahrenheit.value ); } </SCRIPT> <html> <head><title>BehaviorSimple.aspx</title></head> <body onload="Init()"> <div   id="Service"   style="behavior:url(webservice.htc)"   onresult="Service_Result()"></div> Fahrenheit: <input   id="txtFahrenheit"> <input   Type="Button"   Value="Convert!"   OnClick="Button_Click()"> <hr> <span id="lblCelsius"></span> </body> </html> 

The C# version of this code can be found on the CD-ROM.

The page in Listing 23.2 enables you to enter a temperature in degrees Fahrenheit and, by clicking a button, convert the temperature to degrees Celsius (see Figure 23.1). When you click the button, the ToCelsius() method of the TemperatureService Web service is called to perform the conversion.

Figure 23.1. Using the WebService behavior with the Temperature Service .

graphics/23fig01.jpg

The WebService behavior is attached to the page with the following tag:

 
 <div   id="Service"   style="behavior:url(webservice.htc)"   onresult="Service_Result()"></div> 

The behavior is attached to an HTML <div> tag and given the name Service . You can, of course, specify any name that you want for the behavior by supplying another value for the id attribute.

The style attribute actually attaches the behavior by providing the path to the webservice.htc file that implements the WebService behavior. After the WebService behavior is attached to the page, you can access the behavior's methods and properties.

The location of the TemperatureService Web service is provided within the JavaScript Init() function (this function is called by the page's load event). The Init() function contains the following statement:

 
 Service.useService("/webservices/TemperatureService.asmx?WSDL", "TemperatureService"); 

This statement calls the WebService behavior's useService() method, which associates a friendly name with the path to a Web service. In this case, the friendly name TemperatureService is used for the TemperatureService XML Web service. The useService() method also downloads the Web services Description Language (WSDL) file for the Web service. The behavior needs this WSDL file to determine the proper format for the parameters to pass back and forth to the Web service.

When you click the Convert! button, the JavaScript Button_Click function executes the following statement:

 
 intCallID = Service.TemperatureService.callService( "ToCelsius", txtFahrenheit.value ); 

This statement calls the ToCelsius method of the TemperatureService Web service. The first parameter to callService represents the Web method to call. Additional parameters represent parameters passed to the Web method. This statement calls the ToCelsius method with the value of the txtFahrenheit text box.

By default, the WebService behavior calls methods of a Web service asynchronously. The process of calling a Web service method and getting the result is broken into two steps.

When you attached the WebService behavior to the <div> tag, you specified a JavaScript function to handle the result event, which is raised when the Web service method returns a value.

In Listing 23.2, you handled the result event by using the following function:

 
 function Service_Result() {   lblCelsius.innerText = event.result.value; } 

This function grabs the value returned by the Web service ToCelsius method and assigns it to a <span> tag named lblCelsius .

Using a WebService Behavior Callback Function

In the preceding section, you grabbed the value returned by the ToCelsius Web service method within the result event handler. In fact, you can grab the result of a Web method call in two ways: by using an event handler or specifying a callback function.

The page in Listing 23.3 does exactly the same thing as the page in Listing 23.2, except that it uses a callback function rather than an event handler.

Listing 23.3 BehaviorCallback.aspx
[View full width]
 <SCRIPT language="JavaScript"> var intCallID = 0; function Init() {   Service.useService("TemperatureService.asmx?WSDL","TemperatureService"); } function ToCelsius_Result( result ) {   lblCelsius.innerText = result.value; } function Button_Click() {   intCallID = Service.TemperatureService.callService( ToCelsius_Result, "ToCelsius", graphics/ccc.gif txtFahrenheit.value ); } </SCRIPT> <html> <head><title>BehaviorCallback.aspx</title></head> <body onload="Init()"> <div   id="Service"   style="behavior:url(webservice.htc)"></div> Fahrenheit: <input   id="txtFahrenheit"> <input   Type="Button"   Value="Convert!"   OnClick="Button_Click()"> <hr> <span id="lblCelsius"></span> </body> </html> 

The C# version of this code can be found on the CD-ROM.

In Listing 23.3, you call the ToCelsius method by using the following statement:

 
[View full width]
 
[View full width]
intCallID = Service.TemperatureService.callService( ToCelsius_Result, "ToCelsius", graphics/ccc.gif txtFahrenheit.value );

The first parameter passed to the callService method represents a callback function. When the results of the ToCelsius method are returned, the ToCelsius_Result method is called.

When should you use an event handler, and when should you use a callback function? If you need to call only a single Web service method in a page, using an event handler is more convenient. However, if you need to call multiple Web service methods, using a callback function is more convenient because you can create different callback functions that correspond to different Web service method calls.

Catching Errors in a WebService Behavior

Thus far, you haven't added any logic to the pages to handle errors. You've been working under the assumption that a Web service will always be available whenever you attempt to access it. This isn't good programming practice.

You can use the error property of the result object to check for an error. If a Web service cannot be accessed, the error property will have the value True .

You can use the errorDetail object to retrieve a detailed error message. The errorDetail object has three properties:

  • code An error code

  • raw The raw contents of the Simple Object Access Protocol (SOAP) packet returned by the Web service method call

  • string A human-readable error message

The page in Listing 23.4 uses both the error property and errorDetail object to detect and report any errors that might occur when accessing the Web service (see Figure 23.2). The error property and errorDetail object are used in the Service_Result function.

Listing 23.4 BehaviorErrors.aspx
 <SCRIPT language="JavaScript"> var intCallID = 0; function Init() {   Service.useService("TemperatureService.asmx?WSDL","TemperatureService"); } function Service_Result() {   if ( event.result.error )   {     lblCelsius.innerText = event.result.errorDetail.string;   }   else   {   lblCelsius.innerText = event.result.value;   } } function Button_Click() {   intCallID = Service.TemperatureService.callService( "ToCelsius", txtFahrenheit.value ); } </SCRIPT> <html> <head><title>BehaviorErrors.aspx</title></head> <body onload="Init()"> <div   id="Service"   style="behavior:url(webservice.htc)"   onresult="Service_Result()"></div> Fahrenheit: <input   id="txtFahrenheit"> <input   Type="Button"   Value="Convert!"   OnClick="Button_Click()"> <hr> <span id="lblCelsius"></span> </body> </html> 

The C# version of this code can be found on the CD-ROM.

Figure 23.2. Using the error property and errorDetail object.

graphics/23fig02.jpg

Using a WebService Behavior to Perform Partial Page Updates

The feature that makes WebService behaviors so interesting is that they enable you to dynamically update part of a page without reloading the whole page. You can use a WebService behavior to retrieve fresh content at timed intervals and display the content on a page.

This feature of the WebService behavior is illustrated in the page contained in Listing 23.5, which has a featured product section. The contents of the featured product section are automatically updated every five seconds with a call to a Web service.

Listing 23.5 BehaviorRefresh.aspx
 <SCRIPT language="JavaScript"> var intCallID = 0; function Init() {   GetNewFeatured();   setInterval( "GetNewFeatured()", 5000 ) } function GetNewFeatured() {   Service.useService("FeaturedService.asmx?WSDL","FeaturedService");   intCallID = Service.FeaturedService.callService( "GetFeatured" ); } function Service_Result() {   if (event.result.error)   {   divFeatured.innerText = event.result.errorDetail.string;   }   else   {   divFeatured.innerText = event.result.value;   } } </SCRIPT> <html> <head><title>BehaviorRefresh.aspx</title></head> <body onload="Init()"> <table width="600"> <tr>   <td valign="top">   <h2>Welcome to this Web Site!</h2>   Browse this Web site to get great deals on the latest books!   </td>   <td>   <div     id="Service"     style="behavior:url(webservice.htc)"     onresult="Service_Result()"></div>   <div     id="divFeatured"     style="width:200px;padding:10px;border: 1px solid darkgreen">   </div>   </td> </tr> </table> </body> </html> 

The C# version of this code can be found on the CD-ROM.

The page in Listing 23.5 uses the JavaScript setInterval method to execute a function named GetNewFeatured() every five seconds (5000 milliseconds ). The GetNewFeatured() function retrieves a book description from a Web service named FeaturedService . When the Web service method call is complete, the Service_Result function executes and displays the book description within a <div> tag (see Figure 23.3).

Figure 23.3. Partial page update with WebService behavior.

graphics/23fig03.jpg

The code for the FeaturedService Web service is contained in Listing 23.6.

Listing 23.6 FeaturedService.asmx
 <%@ WebService Class="FeaturedService" %> Imports System Imports System.Web.Services Imports System.Data Imports System.Data.SqlClient <WebService( Namespace:="http://yourdomain.com/webservices" )> _ Public Class FeaturedService : Inherits WebService <WebMethod()> Public Function GetFeatured() As String   Dim strSelect As String   Dim conPubs As SqlConnection   Dim dadPubs As SqlDataAdapter   Dim dstTitles As DataSet   Dim drowTitle As DataRow   Dim objRanNum As Random   Dim intRanNum As Integer   strSelect = "SELECT Title, isNull( Notes, '' ) Notes From Titles"   conPubs = New SqlConnection( "Server=localhost;UID=sa;PWD=secret; Database=Pubs" )   dadPubs = New SqlDataAdapter( strSelect, conPubs )   dstTitles = New DataSet   dadPubs.Fill( dstTitles, "Titles" )   objRanNum = New Random   intRanNum = objRanNum.Next( 0, dstTitles.Tables( "Titles" ).Rows.Count )   drowTitle = dstTitles.Tables( "Titles" ).Rows( intRanNum )   Return drowTitle( "Title" ) & " - " & drowTitle( "Notes" ) End Function End Class 

The C# version of this code can be found on the CD-ROM.

The FeaturedService Web service in Listing 23.6 randomly returns information on one book title from the Titles database table. The GetFeatured() method returns a string value that represents the featured title.

Using the WebService Behavior to Retrieve Database Data

Unfortunately, you cannot use the WebService behavior to represent a DataSet or DataTable from an XML Web service. This means that you cannot directly access database data through the WebService behavior.

NOTE

The raw contents of a SOAP packet can be retrieved from the raw property of the result object. In theory, you could parse the raw contents of a SOAP packet that contains a DataSet .


One way to get around this limitation is to convert a DataTable into an array before returning it with a Web service method. This is the approach taken in the page contained in Listing 23.7 and the Web service contained in Listing 23.8 (see Figure 23.4).

Listing 23.7 BehaviorDataTable.aspx
[View full width]
 <SCRIPT language="JavaScript"> var intCallID = 0; function Init() {   Service.useService("ProductsService.asmx?WSDL","ProductsService");   intCallID = Service.ProductsService.callService( Categories_Result, "GetCategories" ); } function Categories_Result( result ) {   var Categories = new Array();   Categories = result.value;   for (var intCounter = 0;intCounter < Categories.length;intCounter++ )   {     var optOption = new Option( Categories[ intCounter ] );     frmProducts.dropCategories.options[ frmProducts.dropCategories.options.length ] = graphics/ccc.gif optOption; } } function Categories_Change( newCategory ) {   var CategoryName = "";   CategoryName = newCategory.options[ newCategory.selectedIndex ].text;   lblCategory.innerText = CategoryName;   intCallID = Service.ProductsService.callService( Products_Result, "GetProducts", graphics/ccc.gif CategoryName ); } function Products_Result( result ) {   var Products = new Array();   Products = result.value;   frmProducts.lstProducts.options.length = 0;   for (var intCounter = 0;intCounter < Products.length;intCounter++ )   {     var optOption = new Option( Products[ intCounter ] );     frmProducts.lstProducts.options[ frmProducts.lstProducts.options.length ] = optOption;   }   frmProducts.lstProducts.style.display = "block"; } </SCRIPT> <html> <head><title>BehaviorDataTable.aspx</title></head> <body onload="Init()"> <div   id="Service"   style="behavior:url(webservice.htc)"></div> <form id="frmProducts"> <select   name="dropCategories"   onchange="Categories_Change( this )">   <option>Select Product Category</option> </select> <p> <span id="lblCategory"></span> <br> <select   name="lstProducts"   size="10"   style="display:none"> </select> </form> </body> </html> 

The C# version of this code can be found on the CD-ROM.

Figure 23.4. Retrieving database data by using the WebService behavior.

graphics/23fig04.jpg

The page in Listing 23.7 contains a drop-down list that enables you to pick a product category. This drop-down list is populated from the Categories table from the Northwind database with a call to the GetCategories() XML Web service method.

When you pick a category, a call to another Web service method is made. The products that match the selected category are retrieved from the Products table through the GetProducts() Web service method and are displayed in a list box. The ProductsService Web service is contained in Listing 23.8.

Listing 23.8 ProductsService.asmx
 <%@ WebService Class="ProductsService" %> Imports System Imports System.Web.Services Imports System.Data Imports System.Data.SqlClient Imports System.Collections <WebService( Namespace:="http://yourdomain.com/webservices" )> _ Public Class ProductsService : Inherits WebService <WebMethod()> Public Function GetCategories() As String()   Dim strSelect As String   Dim conNorthwind As SqlConnection   Dim cmdCategories As SqlCommand   Dim dtrCategories As SqlDataReader   Dim colCategories As ArrayList   strSelect = "SELECT CategoryName FROM Categories"   conNorthwind = New SqlConnection( "Server=localhost;UID=sa;PWD=secret; Database=Northwind" )   cmdCategories = New SqlCommand( strSelect, conNorthwind )   conNorthwind.Open()     dtrCategories = cmdCategories.ExecuteReader()     colCategories = New ArrayList     While dtrCategories.Read       colCategories.Add( dtrCategories( "CategoryName" ) )     End While   conNorthwind.Close()   Return colCategories.ToArray( GetType( System.String ) ) End Function <WebMethod()> Public Function GetProducts( CategoryName As String ) As String()   Dim strSelect As String   Dim conNorthwind As SqlConnection   Dim cmdProducts As SqlCommand   Dim dtrProducts As SqlDataReader   Dim colProducts As ArrayList   CategoryName = Server.UrlDecode( CategoryName )   strSelect = "SELECT ProductName, UnitPrice " & _     "FROM Products, Categories WHERE Products.CategoryID = Categories.CategoryID " & _     "AND CategoryName = @CategoryName"   conNorthwind = New SqlConnection( "Server=localhost;UID=sa;PWD=secret; Database=Northwind" )   cmdProducts = New SqlCommand( strSelect, conNorthwind )   cmdProducts.Parameters.Add( New SQLParameter( "@CategoryName", CategoryName ) )   conNorthwind.Open()     dtrProducts = cmdProducts.ExecuteReader()     colProducts = New ArrayList     While dtrProducts.Read       colProducts.Add( _         dtrProducts( "ProductName" ) & _         String.Format( " - {0:c}", dtrProducts( "UnitPrice" ) ) )     End While   conNorthwind.Close()   Return colProducts.ToArray( GetType( System.String ) ) End Function End Class 

The C# version of this code can be found on the CD-ROM.

Both the GetCategories() and GetProducts() Web service methods work in a similar fashion. Both methods create DataReaders that represent a set of database records. Next, the DataReaders are converted into string arrays that can be consumed by the WebService behavior.



ASP.NET Unleashed
ASP.NET 4 Unleashed
ISBN: 0672331128
EAN: 2147483647
Year: 2003
Pages: 263

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