Handling complex data types returned by Web services using JSON and jQuery in Microsoft.NET and Oracle AS

In this article, I will illustrate how to invoke an Ajax-enabled Web service which returns a complex data type (an array of products) from a Web service in Visual Studio.NET and JDeveloper.


Introduction

JSON is today an alternative to XML for data serialization and transmission over the wire as well as jQuery is becoming the de-facto standard for the client-side script development, not only for the creation of dynamic pages but also for the invocation of Web services compatible with scripting using Ajax. In this article, I want to illustrate how to invoke an Ajax-enabled Web service which returns a complex data type (an array of products) from a Web service. The scenario is an Ajax-enabled Web service which receives a parameter and then returns a list of products, from the Production.Product table in AdventureWorks database, whose ListPrice is less than or equal to the received parameter.

Getting started with the solution in Visual Studio.NET

First step is to define the Ajax-enabled Web service to provide the list of products. Open Visual Studio.NET 2008 and create an ASP.NET Web Application project named JSON_And_jQuery. Add a strongly-typed data set to access the Production.Product table in AdventureWorks database (see Figure 1).

Figure 1

And create a data table and its underlying table adapter in the DSProduction.xsd with the SQL query shown in Listing 1.

select ProductID, [Name], ProductNumber, ListPrice

from Production.Product
where ListPrice<=@ListPriceUpperLimit

Listing 1

Now let's add an Ajax-enabled Web service which sends the query in Listing 1 to SQL Server and receives the result set, and from the result set an array of product is created and sent through the Web service to the client.

We need to define the Product definition for the complex data to be return (see Listing 2).

namespace JSON_And_jQuery

{

    public class Product

    {

        public int ProductID;

        public string ProductName;

        public string ProductNumber;

        public double ListPrice;

    }

}

Listing 2

In order to invoke this Web service from JavaScript code, we need to decorate the Web service with the [ScriptServiceAttribute]. It also denotes that the return string is formatted using the JSON conventions to represent single objects or an array of objects (see Listing 3).

The Web service will return an array of products as an instance of List<Product> and populated with the Product objects return from the result set in Listing 1.

using System;

using System.Collections;

using System.ComponentModel;

using System.Data;

using System.Linq;

using System.Web;

using System.Web.Services;

using System.Web.Services.Protocols;

using System.Xml.Linq;

using System.Web.Script.Services;

using System.Collections.Generic;

using JSON_And_jQuery.DSProductionTableAdapters;

 

namespace JSON_And_jQuery

{

    /// <summary>

    /// Summary description for ProductInfoService

    /// </summary>

    [WebService(Namespace = "http://tempuri.org/")]

    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

    [ScriptService]

    [ToolboxItem(false)]

    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.

    // [System.Web.Script.Services.ScriptService]

    public class ProductInfoService : System.Web.Services.WebService

    {

 

        [WebMethod]

        public List<Product> GetProduct(decimal dListPriceUpperLimit)

        {

            List<Product> arrProduct = new List<Product>();

            DSProduction dsProduction = new DSProduction();

            ProductTableAdapter taProduct = new ProductTableAdapter();

            taProduct.Fill(dsProduction.Product,dListPriceUpperLimit);

 

            foreach(DSProduction.ProductRow rowProduct in dsProduction.Product.Rows)

            {

                Product tmpProduct = new Product();

                tmpProduct.ProductID = rowProduct.ProductID;

                tmpProduct.ProductName = rowProduct.Name;

                tmpProduct.ProductNumber = rowProduct.ProductNumber;

                tmpProduct.ListPrice = rowProduct.ListPrice;

 

                arrProduct.Add(tmpProduct);

            }

 

            return arrProduct;

        }

    }

}

Listing 3

Now let's define the HTML elements in the Default.aspx to invoke the Web service using Ajax and jQuery. We're going to use a <asp:TextBox> Web control to enter the list price upper limit (txtListPriceUpperLimit), a button (btnGetProductList) to invoke the Web service and a panel for displaying the output (see Listing 4).

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="JSON_And_jQuery._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Untitled Page</title>

</head>

<body>

    <form id="form1" runat="server">

    <div>

        Enter the List Price Upper Limit <asp:TextBox ID="txtListPriceUpperLimit" runat="server"> </asp:TextBox><br/>

        <input type="button" id="btnGetProductList" value="Get Product List" /><br/>

        <div id="pnlOutput"></div>

    </div>

    </form>

</body>

</html>

Listing 4

In order to use jQuery, we need to include the jQuery library in the project. I've created the "js" folder and add the jquery-1.3.2.js file in it (see Figure 2).

Figure 2

The code for the jQuery, JSON serialization and the invocation of the Web service using Ajax is shown in Listing 5.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="JSON_And_jQuery._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Untitled Page</title>

    <script src="js/jquery-1.3.2.js" type="text/javascript"></script>

    <script type="text/javascript">

     $(document).ready(

      function()

      {

         $("#btnGetProductList").click

         (

            function(event)

            {

                getProductInformation();

            }

         );

      }

     );

   

      function getProductInformation()

      {

            $.ajax(

            {

                type: "POST",

                url: "ProductInfoService.asmx/GetProduct",

                data: "{dListPriceUpperLimit: " + $('#<%= txtListPriceUpperLimit.ClientID %>').val() + " }",

                contentType: "application/json; charset=utf-8",

                dataType: "json",

                success: function(response)

                {

                    var arrProducts = (typeof response.d) == 'string' ? eval('(' + response.d + ')') : response.d;

                    $('#pnlOutput').empty();

                    for (var i = 0; i < arrProducts.length; i++)

                    {

                        $('#pnlOutput').append('<p><strong>ProductID</strong> '+arrProducts[i].ProductID+' '+

                                               '<strong>Product Name</strong> '+arrProducts[i].ProductName+' '+

                                               '<strong>Product Number</strong> '+arrProducts[i].ProductNumber+' '+

                                               '<strong>List Price</strong> '+arrProducts[i].ListPrice+'</p>');

                    }

 

                },

                failure: function(msg)

                {

                    $('#pnlOutput').append('<p><font color="red">Message error '+msg+' </font></p>');

                }

            });

      }

    </script>

</head>

<body>

    <form id="form1" runat="server">

    <div>

        Enter the List Price Upper Limit <asp:TextBox ID="txtListPriceUpperLimit" runat="server"> </asp:TextBox><br/>

        <input type="button" id="btnGetProductList" value="Get Product List" /><br/>

        <div id="pnlOutput"></div>

    </div>

    </form>

</body>

</html>

Listing 5

In the Default.aspx page, we need to include a reference to the jQuery library using <script type='text/javascript' scr='js/ jquery-1.3.2.js'></script>.

Then, the document.ready function enables setting an event handle for the click event on the "Get Product List" button.

The logic for the invocation of the Web service is implemented in the getProductInformation operation, using the $.ajax method. The request type is POST, and every parameter is passed into the data option, which jQuery syntax to reference the textbox control.

In this example, we've used inline ASP.NET tags to dynamically render the control ID using the ClientID property and the val function returns the value of this textbox control.

The URL specifies the location of the Ajax-enabled Web service.

The content type and data type must be specified to JSON and finally the success and failure defines how to handle the invocation and errors using JavaScript methods.

After the $.ajax method is executed and result data is validated, then the val function enables to convert the JSON string into an array of objects. The array of objects is access through the "d" property. Then the product array is iterated and the property values for each product object are displayed in the pnlOutput panel (<div> tag).

You can see the JSON string after the response is received by the browser using Firebugs extension to Mozila FireFox (see Figure 3).

Figure 3

Getting started with the solution in JDeveloper

Now let's create an example in JDeveloper which consists a JSP page with Ajax and jQuery  in order to call the ProductInfo Web service hosted in ASP.NET.

First of all, let's open JDeveloper and create a new application (see Figure 4).

Figure 4

And an Empty project for the Web components (see Figure 5).

Figure 5

Then, add JSF components to this project. The first component is JSF "Page Flow And Configuration" (the faces-config.xml file) to define the pages and its flow (see Figure 6).

Figure 6

Then drag and drop a JSF Page shape from the JSF Navigation Diagram panel onto the surface of the faces-config.xml file and name it /show_productinfo.jsp. Double-click on this shape and define the page.

In order to use the jQuery library, we need to copy the js directory along with the jquery-1.3.2.js file to the Web content directory in JDeveloper ([ProjectName]\public_html).

Next step is to include the jQuery code in the JSP page inside the <html>/<head> tag in the <f:view> jsp tag (highlighted in yellow). As well as to include the HTML elements to show the button inside the <h:form> jsp tag (highlighted in yellow). See the resulting JSP, HTML and jQuery code in Listing 6.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@ page contentType="text/html;charset=windows-1252"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://xmlns.oracle.com/adf/faces" prefix="af"%>
<%@ taglib uri="http://xmlns.oracle.com/adf/faces/html" prefix="afh"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"%>
<%@ taglib uri="http://xmlns.oracle.com/adf/faces/webcache" prefix="afc"%>
<%@ taglib uri="http://xmlns.oracle.com/adf/industrial/faces" prefix="afi"%>
<f:view>
  <html>
    <head>
      <meta http-equiv="Content-Type"
            content="text/html; charset=windows-1252"/>
      <title> Invoking the Product Information Web service </title>
      <script src="js/jquery-1.3.2.js" type="text/javascript"></script>
      <script type="text/javascript">
       $(document).ready(
        function() 
        {
           $("#btnGetProductList").click
           (
               function(event)
               {
                   getProductInformation();
               }
            );
         }
        );   

        function getProductInformation() 
        {
            $.ajax(
            {
                type: "POST",
                url: http://localhost:1664/ProductInfoService.asmx/GetProduct,
                data: "{dListPriceUpperLimit: " + $('#txtListPriceUpperLimit').val() + " }",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function(response) 
                {
                    var arrProducts = (typeof response.d) == 'string' ? eval('(' + response.d + ')') : response.d;
                    $('#pnlOutput').empty();
                    for (var i = 0; i < arrProducts.length; i++) 
                    {
                        $('#pnlOutput').append('<p><strong>ProductID</strong> '+arrProducts[i].ProductID+' '+ 
                                               '<strong>Product Name</strong> '+arrProducts[i].ProductName+' '+
                                               '<strong>Product Number</strong> '+arrProducts[i].ProductNumber+' '+
                                               '<strong>List Price</strong> '+arrProducts[i].ListPrice+'</p>');
                    }

                },
                failure: function(msg) 
                {
                    $('#pnlOutput').append('<p><font color="red">Message error '+msg+' </font></p>');
                }
            });
        }
    </script>
      
    </head>
    <body>
        <h:form binding="#{backing_show_productinfo.form1}" id="form1">
              <div>
                Enter the List Price Upper Limit 
                <input type="text" id="txtListPriceUpperLimit"><br/>
                <input type="button" id="btnGetProductList" value="Get Product List" /><br/>
                <div id="pnlOutput"></div>
              </div>
        </h:form>
    </body>
  </html>
</f:view>
<%-- oracle-jdev-comment:auto-binding-backing-bean-name:backing_show_productinfo--%>

Listing 6

You can see that a few changes are made to the HTML and jQuery code in the JSP page. For example, we need to the update the URL to the external location of the Web service hosted in ASP.NET environment as well as to change textbox control from the custom ASP control to the HTML text input and the way we reference this control.

After we run the application, the result is resembled in Figure 7.

Figure 7

Conclusion

In this article, I've illustrated how to invoke an Ajax-enabled Web service which returns a complex data type (an array of products) from a Web service in Visual Studio.NET and JDeveloper.