Web Service Calls With jQuery Ajax
Overview
In this article we will explore web service calls with jQuery Ajax from ASP.Net webforms. We will be doing this without the use of an ASP.Net UpdatePanel by performing all Ajax calls directly with jQuery. In my opinion, Ajax calls are far more efficient when making the Ajax call directly because we bypass the overhead of update panels, refreshing the HTML we want to refresh directly, rather than refreshing all the content of the UpdatePanel ContentTemplate HTML on every partial postback. While there is JavaScript code to be written to accomplish this, the impact is minimal and with some usage and experience, the task becomes trivial over time.
The User Interface
We begin by creating an ASP.Net web application in Visual Studio .Net. By default, the project template will create the Default.aspx WebForm which will be a suitable WebForm to use for the purposes of this tutorial. Once the project is created, make sure a reference to the jQuery Library has been made by adding the appropriate script tags to the HEAD element of the Default.aspx WebForm. Let's begin by creating the following user interface:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebServiceCallsArticleUI.aspx.cs" Inherits="jQueryWebServicesAndPageMethods.WebServiceCallsArticleUI" %>
<!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 id="Head1" runat="server">
<title>Web Service Calls With jQuery Ajax</title>
<style type="text/css">
body { font-family: Comic Sans MS; font-size: 10pt; }
h1 { color: #ffffff; background-color: #456984; padding: 3px; font-size: 18px; margin-top: 0px; }
label { margin-top: 5px; display: block; }
input[type=text] { width: 200px; }
select { width: 200px; }
fieldset { margin: 10px; padding: 5px; }
legend { font-weight: bold; }
#wrapper { border: 1px solid #c1c1c1; padding-bottom: 10px; }
</style>
<script src="Assets/Scripts/jquery-1.3.2.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
// Add supporting code here
});
</script>
</head>
<body>
<form id="mainForm" runat="server">
<div id="wrapper">
<h1>
Using jQuery Ajax
</h1>
<fieldset>
<legend>Web Service Calls with Ajax</legend>
<div>
<label for='<%= serviceGreetingTextField.ClientID %>'>
From Web Service:
</label>
<asp:textbox id="serviceGreetingTextField" runat="server" />
<input type="button" id="serviceMethodGetGreeting" value="Greet" />
<input type="button" id="serviceValueReset" value="Reset" />
<img id="serviceGreetingIndicator" src="Assets/Images/Snake456984.gif" alt="Working..." class="progressIndication" />
</div>
</fieldset>
<fieldset>
<legend>Web Service Calls with Ajax (with parameters)</legend>
<div>
<label for='<%= serviceNameField.ClientID %>'>
First Name:
</label>
<asp:textbox id="serviceNameField" runat="server" />
<input type="button" id="getServiceNameGreeting" value="Greet" />
<input type="button" id="resetServiceNameGreeting" value="Reset" />
<label for='<%= serviceNameGreetingField.ClientID %>'>
Greeting:
</label>
<asp:textbox id="serviceNameGreetingField" runat="server" />
<img id="serviceNameGreetingIndicator" src="Assets/Images/Snake456984.gif" alt="Working..." class="progressIndication" />
</div>
</fieldset>
<fieldset>
<legend>Adding Items to a List From a WebService</legend>
<div>
<label for='<%= testList.ClientID %>'>
List Items:
</label>
<asp:dropdownlist id="testList" runat="server">
<asp:listitem value="-1" text="-- Select --" />
</asp:dropdownlist>
<input type="button" id="testListAddItems" value="Get Items" />
<input type="button" id="testListReset" value="Reset" />
<img id="testListIndicator" src="Assets/Images/Snake456984.gif" alt="Working..." class="progressIndication" />
</div>
</fieldset>
</div>
</form>
</body>
</html>
Once the UI is created, we should end up with something similar to the following screen capture:
While we are at it, do save the progress indicator image shown in the screen capture by right clicking the image below and saving it to the images folder in your web application. We will be using this image as a progress indicator for each of our fieldset elements as we execute each Ajax call.
Now that we have a UI to work with we can assume that we will be making 3 different Ajax calls. These are:
- A call to retrieve a greeting from a web service similar to "Hello World"
- A call to retrieve a greeting from a web service by passing a first name parameter
- A call to retrieve a list of greetings from a web service that will populate a dropdown list
The web methods we will be calling have been made extremely simple just for the purpose of demonstrating the concepts involved in making these Ajax calls. However, using this methodology, you are certainly able to create more complex methods that return more complex data. That said, the first two calls will be returning simple strings, while the last call we will use for populating the dropdown list, will return an object of type
List<string>
Let's get started!
Web Service Implementation
The first thing that we must do is create a web service application in the same solution where we created our web application. I chose to name this project
- SampleServices
Once the web service application project has been created, the application should be converted to an IIS web application if IIS is available in the development system. To do so, follow these steps:
- Right click the web service application project and select "Properties" from the context menu
- In the properties window, select the "Web" tab on the left side of the properties window.
- Click the "Use Local IIS server" option towards the bottom of the options window
- While I chose to use "http://localhost/SampleServices" for my virtual directory, you may chose an URL of your choice.
- Save the properties and close the properties window
Now that we have a local IIS site, we are able to provide this address to the URL parameter of the ajax call within the jQuery code. By default, when the web service application was created, Visual Studio created a default web service called
- Service1.asmx
Go ahead an delete that service and add a new one called
- SimpleService.asmx
Once the new service class has been created, right click the file and select "View Code" from the context menu and add the following code:
namespace SampleServices
{
/// <summary>
/// Summary description for SimpleService
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class SimpleService : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
System.Threading.Thread.Sleep(500);
return "Hello World From Web Service";
}
[WebMethod]
public string HelloWho(string name)
{
System.Threading.Thread.Sleep(500);
return string.Format("Hello {0}!", name);
}
[WebMethod]
public List<string> GreetingList()
{
System.Threading.Thread.Sleep(500);
List<string> retVal = new List<string>();
retVal.Add("Jim");
retVal.Add("John");
retVal.Add("Joe");
return retVal;
}
}
}
We now have three web methods with the following names and purpose:
- HelloWorld: Will return a hard coded greeting string
- HelloWho: Will return a formatted string with a parameter passed into it by the caller
- GreetingList: Will return a string array containing names that will be further formatted to show greetings in list fashion
Once the service is complete, build the project and if all goes well, close the web service class editor as we have now fully implemented the web service itself and will be focusing on the JavaScript we need in order to bring the UI and the web service work together.
jQuery Implementation
If not already open for editing, open the Default.aspx webform in source view and locate the following empty script tag we created along with the UI:
<script type="text/javascript">
$(document).ready(function() {
// Add supporting code here
});
</script>
We will be doing the bulk of our work inside of the "$(document).ready" event. One of the nicest things about jQuery is the way that it wires up all page control events when the document first loads. This way, we are not constrained into coding events into our html elements and thus truly separating UI implementation from UI behavior. We will then take advantage of this functionality and begin wiring up a set of element events that when fired, will in turn execute Ajax calls against the web service we have already created. Let's begin by adding the following code inside of the "$(document).ready" event carefully noting the variable "indicatorID which resides outside of "$(document).ready":
// Progress indicator placeholder var
var indicatorID = '';
$(document).ready(function() {
// Hide all progress indicators
$('.progressIndication').hide();
// Clears reseting of web service value
$('#serviceValueReset').click(function() {
if ($('#serviceGreetingTextField').val() == '')
alert('The field is empty');
else
$('#serviceGreetingTextField').val('');
});
// Retrieves a greeting from a web service
$('#serviceMethodGetGreeting').click(function() {
// Set indicator id
indicatorID = '#serviceGreetingIndicator';
// Clear field value
$('#<%= serviceGreetingTextField.ClientID %>').val('');
// Ajax URL
var serviceUrl = 'http://localhost/SampleServices/SimpleService.asmx/HelloWorld';
// Execute Ajax call
$.ajax({
type: 'POST',
url: serviceUrl,
data: '{}',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function(result) {
$('#<%= serviceGreetingTextField.ClientID %>').val(result.d);
},
error: function() {
alert('An error occurred while accessing the the following web service:\n'
+ serviceUrl);
}
});
});
});
Outside of the "$(document).ready" event add the following code:
// Progress indicator
$(document).ajaxStart(function() {
if (!(indicatorID == '')) {
$(indicatorID).show();
}
}).ajaxStop(function() {
if (!(indicatorID == '')) {
$(indicatorID).hide();
indicatorID = '';
}
});
We have accomplished three things here:
- $('#serviceValueReset').click: We have created an event for the reset button on the first fieldset element that will clear any data already present in any of the fields located within the first fieldset.
- $('#serviceMethodGetGreeting').click: We have created an event that will execute the Ajax call against the web service method that will in turn return a value that will populate the "serviceGreetingTextField" textbox.
- $(document).ajaxStart().ajaxStop(): We have created the necessary plumbing that will allow our webform to display a progress indicator next to the elements that will be affected by the Ajax call
...and this is how this works:
- $('#serviceValueReset').click references the textbox element and detects whether it is necessary to clear it or not, alerting the user of this fact. If the field has content, it simply clears it by setting its value to an empty string.
- $('#serviceMethodGetGreeting').click responds to click events fired by the "serviceMethodGetGreeting" button. Next it sets the "indicatorID" variable to the indicator image ID associated with the element being updated by the ajax call to the web service. After this is done, the textbox is cleared of any content by setting its value to an empry string. Now that the form is ready to be updated, the web service URL along with the method we intend to call is stored in string format into a variable. It is important to make sure this URL is formatted correctly or else the call will simply fail.
-
$.ajax is given all the options it needs in order to execute the call to the web service by setting the following options
- type: Since we are using JSON, this value is set to use the "POST" form method.
- url: This is the web service [URL + "/" + METHOD_NAME]
- data: Since we are not passing parameters to the web service, we pass the JSON equivalent of NULL "{}"
- contentType: The application content type which happens to be "application/json; charset=utf-8"
- dataType: THis value is set to "json" since this is the format in which we are making the call to the web service
- success: This is a callback function that will be executed if the Ajax call was successful and therefore the function we use in order to update the form elements
- error: This is the callback function that will be executed in the unfortunate event an error occurs. It simply displays an alert to the user stating that an error has occurred.
- $(document).ajaxStart().ajaxStop(): This is where our progress indicators are shown or hidden. They are displayed when the Ajax call is initiated and hidden upon termination. This is why the "indicatorID" variable is set when the "serviceMethodGetGreeting" is fired. In this way, the "$(document).ajaxStart().ajaxStop()" events are aware of which indicator to show or hide and when.
jQuery Implementation... The Rest
Having now implemented the support code for the first fieldset element on the webform, we can now add the rest of the code and go through the highlights of what it is doing differently from the code we've just implemented. Add the following code below the "$('#serviceMethodGetGreeting').click" event block:
// Retrieves a greeting from a web service by passing parameters
$('#getServiceNameGreeting').click(function() {
var firstName = $('#<%= serviceNameField.ClientID %>').val();
if (firstName != '') {
// Set indicator id
indicatorID = '#serviceNameGreetingIndicator';
// Clear field value
$('#<%= serviceNameGreetingField.ClientID %>').val('');
// Ajax URL.
var serviceUrl = 'http://localhost/SampleServices/SimpleService.asmx/HelloWho';
// Get parameter format
var format = "{'name':'" + firstName + "'}";
// Execute Ajax call
$.ajax({
type: 'POST',
url: serviceUrl,
data: format,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function(result) {
$('#<%= serviceNameGreetingField.ClientID %>').val(result.d);
},
error: function() {
alert('An error occurred while accessing the the following web service:\n'
+ serviceUrl);
}
});
} else {
alert('First Name is required');
}
});
// Clears reseting of web service value
$('#resetServiceNameGreeting').click(function() {
if ($('#serviceNameField').val() == '' || $('#serviceNameField').val() == '')
alert('The field is empty');
else {
$('#serviceNameField').val('');
$('#serviceNameGreetingField').val('');
}
});
$('#testListAddItems').click(function() {
// Set indicator id
indicatorID = '#testListIndicator';
// Ajax URL.
var serviceUrl = 'http://localhost/SampleServices/SimpleService.asmx/GreetingList';
// Execute Ajax call
$.ajax({
type: 'POST',
url: serviceUrl,
data: '{}',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function(result) {
$.each(result.d, function(i, text) {
$('#<%= testList.ClientID %>').append($('<option></option>').val(i).html('Hello ' + text));
});
},
error: function(xmlHttpRequest, status, error) {
var errorStatus = xmlHttpRequest.status;
var errorText = xmlHttpRequest.responseText;
var statusText = xmlHttpRequest.statusText;
alert('Error Status: ' + errorStatus + '\n'
+ 'Error Message: ' + errorText + '\n'
+ 'Status Info: ' + statusText + '\n');
}
});
});
// Resets the test list
$('#testListReset').click(function() {
$('#<%= testList.ClientID %> >option').remove();
$('#<%= testList.ClientID %>').append($('<option></option>').val('-1').html('-- Select --'));
});
And now the highlights...
As seen in the first example, an event is attached to each of the buttons that will trigger an Ajax call. In this case, the "$('#getServiceNameGreeting').click" event is attached to the "getServiceNameGreeting" button. In addition to the usual boiler-plate code in which we set up the service URL and Ajax parameters, we created a parameter format variable that contains the "parameter name/value" pair that must be passed to the web service for the intended web service call. This parameter format is very important because a simple typo will force the Ajax event to fire the "error" callback instead of the "success" callback and therefore failing the exacution of the web service call. The syntax for this format is not very complicated but rather easy to mess up, especially when more than one parameter must be used. In short, if the WebMethod signature contains parameters "p1, p2, p3" then our parameter string should look like the following:
- {'p1':'v1','p2':'v2','p3':'v3'}
As seen above, good attention to detail should be exercised when building these strings because even though it is a very simple string format, it is even simpler to get mess up. Once we get passed the parameter format, the Ajax call is exacuted against the web service in much the same fashion as before
The last part of the implementation deals with binding a dropdown list from yet another web service method. In this case, the web service call is nearly identical to the first service call in our implementation. The one difference is that while the first two code implementations dealt with string results being returned from the web services, the last web method we will call will return an object of type List
Understanding this, all that remains is the addition tof the elements to our dropdown list. This too, we shall accomplish with jQuery by iterating through the returned items by the web service by way of the "success" callback function.
Conclusion
In this we have covered the very basic concepts of executing Ajax calls against web services, returning values, arrays, passing parameters and manipulating UI elements to respond to Ajax activity. Additionally we have explored the flexibility that making these calls manually will give you as you dig deeper and move away from the usual update panel here and update progress there pattern of ASP.Net Ajax controls. While these methods are useful and certainly worth learning, learning how not to depend on those controls will be a skill you will thank your self over and over again for learning when blackbox code such as that of ASP.Net Ajax fails or behaves buggy and erratic.
Get the source code for this article.







