Ads Header

Thursday, January 13, 2011

Consuming Web Service Using ASP.NET AJAX

ASP.NET AJAX provides the power of asynchronous JavaScript and XML to your web sites. AJAX makes web pages more responsive and interactive by reducing page refreshes or postbacks. It harnesses the power of client-side JavaScript and the XML HTTP object to provide these features.
Although AJAX is essentially a client-side technique, most of its real-world deployments call for server-side processing. Most commonly, the data manipulated by your web site will reside in some RDBMS on the server. To make AJAX really useful, you need an easy and robust way to deal with this server-side data. Fortunately, ASP.NET AJAX provides a sound infrastructure for doing just that. AJAX communication happens between your browser and the server over the Internet. Naturally, web services can play a significant role in data transport and overall communication between the client and the server. This article shows how ASP.NET AJAX can consume ASP.NET web services.

Software Requirements

All the examples in this article are developed using the RC build of ASP.NET AJAX that you can download from ajax.asp.net. Moreover, you need to have SQL Server 2005 (Express Edition will do) with the Northwind database installed. The examples use Visual Studio 2005 as the IDE.

Example Scenario

The example develops a web form that acts as a data entry page for an Employees table of the Northwind database. Using ASP.NET AJAX features, this data entry page will consume a web service that allows you to SELECT, INSERT, UPDATE, and DELETE employees.

Creating the Web Service

    To begin with, create a new web site using Visual Studio 2005. Notice that installing ASP.NET AJAX adds project templates to the New Web Site dialog, including the "ASP.NET AJAX Enabled Web Site" template (see Figure 1).





    Figure 1: The New Web Site Dialog with Added Templates
    A web site created using the "ASP.NET AJAX Enabled Web Site" template is different from a normal web site in the following ways:
    • It has a web.config file with a lot of ASP.NET AJAX-specific configuration information.
    • It refers System.Web.Extensions assembly.
    Of course, you can modify a normal web site to make it AJAX enabled, but this template simplifies your job.
    Now that you have created a new web site, add a new web service to it and name it EmployeeService.asmx. The EmployeeService will contain five web methods (see Table 1).
    Method Name Description
    GetEmployees() Returns a list of employees from the Employees table. The list is returned in the form of an array of Employee objects.
    GetEmployee() Accepts an EmployeeID and returns its details as an Employee object.
    Insert() Adds a new employee to the Employees table.
    Update() Updates an existing employee from the Employees table.
    Delete() Deletes an existing employee from the Employees table.
    Table 1. Web Methods in EmployeeService
    The GetEmployees() and GetEmployee() methods return data in the form of Employee object(s). Therefore, you first need to create a class called Employee. Right-click the App_Code folder of your web site and choose "Add New Item...". Add a new class called Employee. The following is the complete code that makes the Employee class:
    public class Employee
    {
       private int intEmployeeID;
       private string strFirstName;
       private string strLastName;
       public int EmployeeID
       {
          get
          {
             return intEmployeeID;
          }
          set
          {
             intEmployeeID = value;
          }
       }
       public string FirstName
       {
          get
          {
             return strFirstName;
          }
          set
          {
             strFirstName = value;
          }
       }
       public string LastName
       {
          get
          {
             return strLastName;
          }
          set
          {
             strLastName = value;
          }
       }
    }
    The Employee class declares three provate variables for storing employee ID, first name, and last name, respectively. The three variables are wrapped inside three public properties: EmployeeID, FirstName, and LastName.
    Open the web.config file and add a <connectionStrings> section as follows:
    <connectionStrings>
       <add name="connstr" connectionString=
            "data source=.\sqlexpress;
            initial catalog=northwind;
            integrated security=true"/>
    </connectionStrings>
    This stores a database connection string that points to the Northwind database. Make sure to change SQL Server name/IP and authentication details to match your environment.
    Now, open EmployeeService.cs and add the following code:
    private string strConn =
       "";
    public EmployeeService()
    {
       strConn = ConfigurationManager.ConnectionStrings["connstr"].
                 ConnectionString;
    }
    The code uses the ConfigurationManager class to read the connection string from the config file and stores it in a class-level variable called strConn. This variable is used further by all the other web methods.
    Now, add the GetEmployees web method as follows:
    [WebMethod]
    public Employee[] GetEmployees()
    {
       SqlConnection cnn = new SqlConnection(strConn);
       cnn.Open();
       SqlCommand cmd            = new SqlCommand();
       cmd.Connection            = cnn;
       cmd.CommandText           = "select employeeid,firstname,
                                    lastname from employees";
       SqlDataReader reader      = cmd.ExecuteReader();
       List<Employee> list = new List<Employee>();
       while (reader.Read())
       {
          Employee emp   = new Employee();
          emp.EmployeeID = reader.GetInt32(0);
          emp.FirstName  = reader.GetString(1);
          emp.LastName   = reader.GetString(2);
          list.Add(emp);
       }
       reader.Close();
       cnn.Close();
       return list.ToArray();
    }
    The code creates new SqlConnection and SqlCommand objects. It then executes a SELECT query and fetches EmployeeID, FirstName, and LastName columns from the Employees table. The results are retrieved as SqlDataReader instances. Then, a generic-based List of Employee objects is created. A while loop iterates through the SqlDataReader. With each iteration, a new Employee object is created and its EmployeeID, FirstName, and LastName properties are set. The Employee object then is added to the List. After the while loop completes, SqlDataReader and SqlConnection are closed. The return type of the GetEmployees() web method is an array of Employee objects. Hence, the generic List is converted into Employee array using the ToArray() method of the List class


    [WebMethod]
    public Employee GetEmployee(int pEmployeeId)
    {
       SqlConnection cnn = new SqlConnection(strConn);
       cnn.Open();
       SqlCommand cmd       = new SqlCommand();
       cmd.Connection       = cnn;
       cmd.CommandText      = "select employeeid,firstname,lastname
                               from employees where employeeid=@id";
       SqlParameter id      = new SqlParameter("@id", pEmployeeId);
       cmd.Parameters.Add(id);
       SqlDataReader reader = cmd.ExecuteReader();
       Employee emp         = new Employee();
       while (reader.Read())
       {
          emp.EmployeeID = reader.GetInt32(0);
          emp.FirstName  = reader.GetString(1);
          emp.LastName   = reader.GetString(2);
       }
       reader.Close();
       cnn.Close();
       return emp;
    }
    The GetEmployee() web method accepts an employee ID that is to be returned. The code is very similar to the previous code but this time it fetches only one employee. Note that you used SqlParameter to represent the passed EmployeeID.
    Now you can add the Insert(), Update(), and Delete() web methods as follows:
    [WebMethod]
    public int Insert(string pFirstName, string pLastName)
    {
       SqlConnection cnn  = new SqlConnection(strConn);
       cnn.Open();
       SqlCommand cmd     = new SqlCommand();
       cmd.Connection     = cnn;
       cmd.CommandText    = "insert into employees(firstname,lastname)
                             values (@fname,@lname)";
       SqlParameter fname = new SqlParameter("@fname", pFirstName);
       SqlParameter lname = new SqlParameter("@lname", pLastName);
       cmd.Parameters.Add(fname);
       cmd.Parameters.Add(lname);
       int i = cmd.ExecuteNonQuery();
       cnn.Close();
       return i;
    }
    [WebMethod]
    public int Update(int pEmployeeId,string pFirstName, string pLastName)
    {
       SqlConnection cnn  = new SqlConnection(strConn);
       cnn.Open();
       SqlCommand cmd     = new SqlCommand();
       cmd.Connection     = cnn;
       cmd.CommandText    = "update employees set firstname=@fname,
                             lastname=@lname where employeeid=@id";
       SqlParameter fname = new SqlParameter("@fname", pFirstName);
       SqlParameter lname = new SqlParameter("@lname", pLastName);
       SqlParameter id = new SqlParameter("@id", pEmployeeId);
       cmd.Parameters.Add(fname);
       cmd.Parameters.Add(lname);
       cmd.Parameters.Add(id);
       int i = cmd.ExecuteNonQuery();
       cnn.Close();
       return i;
    }
    [WebMethod]
    public int Delete(int pEmployeeId)
    {
       SqlConnection cnn = new SqlConnection(strConn);
       cnn.Open();
       SqlCommand cmd  = new SqlCommand();
       cmd.Connection  = cnn;
       cmd.CommandText = "delete from employees where employeeid=@id";
       SqlParameter id = new SqlParameter("@id", pEmployeeId);
       cmd.Parameters.Add(id);
       int i = cmd.ExecuteNonQuery();
       cnn.Close();
       return i;
    }
    The Insert() web method accepts the first name and last name of the employee to be added. It then creates an instance each of SqlConnection and SqlCommand and executes the INSERT statement using the ExecuteNonQuery() method of the SqlCommand object. Similarly, the Update() web method accepts the employee ID to be updated, along with new values for first name and last name, and fires an UPDATE statement. Finally, the Delete() web method accepts an employee ID that is to be deleted and fires a DELETE statement.
    This completes your web service. To this point, you have not done anything specific to AJAX functionality. Now, it's time to do just that. Modify your web service class definition as follows:
    using System.Web.Script.Services;
    ...
    ...
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ScriptService]
    public class EmployeeService : System.Web.Services.WebService
    {
       ...
       ...
    Notice the lines marked in bold. You have imported a namespace System.Web.Script.Services, which comes from the System.Web.Extensions assembly. The [ScriptService] attribute you'll use later is supplied by this namespace. The [ScriptService] attribute enables the web service to be called from the client-side JavaScript (i.e., ASP.NET AJAX).
    That's it! You are now ready to consume your web service from ASP.NET AJAX.

    How to Consume the Web Service

    In this section, you will create a web form that acts as a data entry page for the Employees table by consuming the web service you just created. To begin, add a new web form called EmployeeServiceClient.aspx to the web site. Open the toolbox by selecting the View > Toolbox menu option. On the toolbox, locate a node titled AJAX Extensions (see Figure 2).

    Figure 2: The New Web Site Dialog with Added Templates
    The AJAX Extensions node displays all the ASP.NET AJAX components that you can use on a web form. Drag and drop a ScriptManager component on the web form. Every web form making use of ASP.NET AJAX needs one ScriptManager component. Open the properties window for the ScriptManager. Locate its Services property and open the Service Reference collection editor as shown in Figure 3.



    Click here for a larger image.

    Figure 3: The Service Reference Collection Editor Click the Add button at the bottom of the dialog and set the Path property to the virtual path of the web service (in other words, EmployeeService.asmx). This will generate the following markup in the web form file:
    <asp:ScriptManager ID="ScriptManager1" runat="server" >
       <Services>
          <asp:ServiceReference Path="EmployeeService.asmx" />
       </Services>
    </asp:ScriptManager>
    For each web service that you want to consume, you need one <asp:ServiceReference> element inside the <asp:ScriptManager> section. The <asp:ServiceReference> tag registers a web service to use in the current web form.

    Now, design the web form as shown in Figure 4.

    Figure 4: Design the Web Form
    The web form consists of a dropdown (<SELECT>) that lists all the existing employee IDs. Once you select a specific ID, details of that employee are displayed in the two textboxes. You then can update them. To add an employee, you simply need to enter the first name and last name and click the Insert button. Similarly, you can delete an employee by selecting employee ID in the dropdown and clicking the Delete button. A success or failure message is displayed once the INSERT, UPDATE, or DELETE operation is over. The following is the complete markup of the web form:
    <table>
       <tr>
          <td colspan="2">
             <asp:Label ID="Label4" runat="server" Font-Size="X-Large"
                        Text="Employee Management">
             </asp:Label></td>
       </tr>
       <tr>
          <td style="width: 100px">
             <asp:Label ID="Label1" runat="server"
                        Text="Employee ID :"></asp:Label></td>
          <td style="width: 100px">
             <select id="Select1" >
             </select>
          </td>
       </tr>
       <tr>
          <td style="width: 100px">
             <asp:Label ID="Label2" runat="server"
                        Text="First Name :"></asp:Label></td>
          <td style="width: 100px">
             <input id="Text1" type="text" /></td>
       </tr>
       <tr>
          <td style="width: 100px">
             <asp:Label ID="Label3" runat="server"
                        Text="Last Name :"></asp:Label></td>
          <td style="width: 100px">
             <input id="Text2" type="text" /></td>
       </tr>
       <tr>
          <td align="center" colspan="2">
             <input id="Button3" type="button" value="Insert" />
             <input id="Button4" type="button" value="Update" />
             <input id="Button5" type="button" value="Delete" />
          </td>
       </tr>
       <tr>
          <td align="center" colspan="2">
             <span id="lblMsg" style="font-weight: bold;
                   color: red;"></span>
          </td>
       </tr>
    </table>
    Notice one important thing: You did not use ASP.NET server controls such as DropDownList, TextBox, and Button. Instead, you used traditional HTML controls such as <SELECT> and <INPUT>. This is because you want to call your web service from client-side JavaScript and not from server-side code. Also, notice the <SPAN> tag at the bottom. It will be used for displaying success or failure messages.
    Next, add a <script> section inside the <head> HTML element. Add a function called CallWebMethod() as shown below:
    function CallWebMethod(methodType)
    {
       switch(methodType)
       {
          case "select":
             EmployeeService.GetEmployees(FillEmployeeList,ErrorHandler,
                                          TimeOutHandler);
             break;
          case "selectone":
             var select=document.getElementById("Select1");
             var empid=select.options[select.selectedIndex].value;
             EmployeeService.GetEmployee(empid,DisplayEmployeeDetails,
                                         ErrorHandler,TimeOutHandler);
             break;
          case "insert":
             var text1=document.getElementById("Text1");
             var text2=document.getElementById("Text2");
             EmployeeService.Insert(text1.value,text2.value,
                                    InsertEmployee,ErrorHandler,
                                    TimeOutHandler);
             break;
          case "update":
             var select=document.getElementById("Select1");
             var empid=select.options[select.selectedIndex].value;
             var text1=document.getElementById("Text1");
             var text2=document.getElementById("Text2");
             var emp=new Employee();
             emp.EmployeeID=empid;
             emp.FirstName=text1.value;
             emp.LastName=text2.value;
             EmployeeService.Update(empid,text1.value,text2.value,
                                    UpdateEmployee,ErrorHandler,
                                    TimeOutHandler);
             break;
          case "delete":
             var select=document.getElementById("Select1");
             var empid=select.options[select.selectedIndex].value;
             EmployeeService.Delete(empid,DeleteEmployee,ErrorHandler,
                                    TimeOutHandler);
             break;
       }
    }
    The CallWebMethod() function is a central function that makes calls to the web service. The function accepts a string parameter indicating the method to be called and then calls that method. It contains a switch statement that checks off the method to be called. Each case block calls one web method. Notice how the web method has been called. The ASP.NET AJAX framework automatically creates a JavaScript proxy class for the web service. The proxy class has the same name as the web service. So, the EmployeeService in the above code is not the actual web service class but a JavaScript proxy class. The proxy contains all the web methods of the original web service. In addition to the original web method parameters, each method can have three extra parameters.
    The first extra parameter is a JavaScript function that should be called when the web method call is successfully completed. Remember that any AJAX communication between client and server is asynchronous. Hence, this function is necessary to capture the return value of the web method. The second parameter is a JavaScript function that is called in the event of error. Finally, the third extra parameter is a JavaScript function that is called if a timeout occurs during the web method call.
    In the first case ("select"), you simply call the GetEmployees() method. In the second case ("selectone"), you call the GetEmployee() method. The employee ID is picked up from the dropdown using traditional JavaScript code. Similarly, the third, fourth, and fifth case blocks call the Insert(), Update(), and Delete() methods, respectively.
    The above code uses five JavaScript functions that are called when the respective web method calls are successful: FillEmployeeList(), DisplayEmployeeDetails(), InsertEmployee(), UpdateEmployee(), and DeleteEmployee(). Each of these functions accepts a single parameter that represents the return value of the corresponding web method:
    function FillEmployeeList(result)
    {
       var select=document.getElementById("Select1");
       for(var i=0;i<result.length;i++)
       {
          var option=new Option(result[i].EmployeeID,
                                result[i].EmployeeID);
          select.options.add(option);
       }
    }
    function DisplayEmployeeDetails(result)
    {
       var text1=document.getElementById("Text1");
       var text2=document.getElementById("Text2");
       text1.innerText=result.FirstName;
       text2.innerText=result.LastName;
       var lblMsg=document.getElementById("lblMsg");
       lblMsg.innerText="";
    }
    function InsertEmployee(result)
    {
       if(result>0)
       {
          var lblMsg=document.getElementById("lblMsg");
          lblMsg.innerText="Employee added successfully!";
       }
       else
       {
          var lblMsg=document.getElementById("lblMsg");
          lblMsg.innerText="Error occurred while adding new employee!";
       }
    }
    function UpdateEmployee(result)
    {
       if(result>0)
       {
          var lblMsg=document.getElementById("lblMsg");
          lblMsg.innerText="Employee updated successfully!";
       }
       else
       {
          var lblMsg=document.getElementById("lblMsg");
          lblMsg.innerText="Error occurred while updating the employee!";
       }
    }
    function DeleteEmployee(result)
    {
       if(result>0)
       {
          var lblMsg=document.getElementById("lblMsg");
          lblMsg.innerText="Employee deleted successfully!";
       }
       else
       {
          var lblMsg=document.getElementById("lblMsg");
          lblMsg.innerText="Error occurred while deleting employee!";
       }
    }
    The FillEmployeeList() function receives an array of Employee objects as a parameter. Recollect that your GetEmployees() web method returns an array of Employee objects. It then iterates through the array. With each iteration, a new OPTION element is created and added to the dropdown (in other words, <SELECT>). The DisplayEmployeeDetails() function receives an Employee object containing details about an employee. It simply displays those details in the two textboxes. The InsertEmployee(), UpdateEmployee(), and DeleteEmployee() functions receive an integer indicating the number of records affected by the INSERT, UPDATE, and DELETE operations, respectively. A result greater than zero indicates success and they display a success message in the <SPAN> tag. Otherwise, they display an error message. When your page is displayed for the first time, you need to populate the dropdown list with the existing employee IDs. This is done by calling the CallWebMethod() method in a special function named pageLoad():
    function pageLoad()
    {
       CallWebMethod("select");
    }

    0 Responses to “Consuming Web Service Using ASP.NET AJAX”

    Post a Comment