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.

Consuming Web Service Using ASP.NET AJAX

Next, add a web method called GetEmployee() as follows:

[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).

[Bipin2.jpg]

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.

[Bipin3.jpg]

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.

Consuming Web Service Using ASP.NET AJAX

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

[Bipin4.jpg]

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");
}

Consuming Web Service Using ASP.NET AJAX

The pageLoad() function gets called automatically when the web page is loaded in the client browser. Finally, the error handler and timeout handler functions look like this:

function ErrorHandler(result)
{
   var msg=result.get_exceptionType() + "\r\n";
   msg += result.get_message() + "\r\n";
   msg += result.get_stackTrace();
   alert(msg);
}

function TimeOutHandler(result)
{
   alert("Timeout :" + result);
}

The TimeOutHandler() function is called whenever a web method times out. It simply shows an alert to the user. The ErrorHandler() function is called whenever there is any error. The result parameter received by this method provides three methods: get_exceptionType(), get_message(), and get_stackTrace(). These three methods return the type of exception, detailed error message, and stack trace, respectively. The ErrorHandler() function simply displays an alert to the end user.

Testing the Web Page

Now that you have developed the web service and the client application, it's time to test them. Run the web form and try inserting, updating, or deleting employees. Figure 5 shows the web form after updating an employee.

[Bipin5.jpg]

Figure 5: Web Form After Updating an Employee

To test the error handler function, deliberately initialize the connection string to an empty string and run the web page again. This time, you should see an alert as shown in Figure 6.

[Bipin6.jpg]

Figure 6: ConnectionString Property Alert

Calling External Web Services

In this example, the EmployeeService was part of your web site. Sometimes, you may need to call web services that are not hosted by your domain at all. ASP.NET AJAX internally relies on the XML HTTP object, which for security reasons cannot communicate outside the originating web site. That means the above technique won't work for external web services. Unfortunately, ASP.NET AJAX does not have a direct solution to this issue (at least in the RC version). However, Microsoft has released a "bridge" technology that is still in CTP stages. You can use the bridge to call a wrapper class residing in your web site, which in turn calls the actual web service. In the current RC version, you can create a wrapper web service in your web site, which in turn calls the original web service. From the client application, you then can call your wrapper web service and achieve the communication. The following is an outline of the necessary steps:

  1. Add a web reference to the external web service in your web site.
  2. Create a new web service in your web site.
  3. In the newly created web service, provide wrapper web methods that call the external web methods via web reference.
  4. Call this newly added web service from the client application as described in this article.

Infrastructure for Calling ASP.NET Web Services

ASP.NET AJAX provides a complete infrastructure for calling ASP.NET web services from client-side JavaScript. You can easily integrate server data with the user-responsive web pages using AJAX. All you need to do is mark your web service with the [ScriptService] attribute. The ASP.NET AJAX framework generates a JavaScript proxy for your web service. The proxy then is used to call the web methods.

About the Author

Bipin Joshi is the founder and owner of BinaryIntellect Consulting, where he conducts professional training programs on .NET technologies. He is the author of Developer's Guide to ASP.NET 2.0 and co-author of three WROX press books on .NET 1.x. He also is a Microsoft MVP, member of ASPInsiders, MCAD, and MCT.



About the Author

Bipin Joshi

Bipin Joshi is a blogger and writes about apparently unrelated topics - Yoga & technology! A former Software Consultant by profession, Bipin has been programming since 1995 and has been working with the .NET framework ever since its inception. He has authored or co-authored half a dozen books and numerous articles on .NET technologies. He has also penned a few books on Yoga. He was a well known technology author, trainer and an active member of Microsoft developer community before he decided to take a backseat from the mainstream IT circle and dedicate himself completely to spiritual path. Having embraced Yoga way of life he now codes for fun and writes on his blogs. He can also be reached there.

Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: April 22, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Database professionals — whether developers or DBAs — can often save valuable time by learning to get the most from their new or existing productivity tools. Whether you're responsible for managing database projects, performing database health checks and reporting, analyzing code, or measuring software engineering metrics, it's likely you're not taking advantage of some of the lesser-known features of Toad from Dell. Attend this live …

  • On-demand Event Event Date: March 27, 2014 Teams need to deliver quality software faster and need integrated agile planning, task tracking, source control, auto deploy with continuous builds and a configurable process to adapt to the way you work. Rational Team Concert and DevOps Services (JazzHub) have everything you need to build great software, integrated seamlessly together right out of the box or available immediately in the cloud. And with the Rational Team Concert Client, you can connect your …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds