Building Interactive User Interfaces with Microsoft ASP.NET AJAX: Retrieving Server-Side Data Using Web Services
By Scott Mitchell
A Multipart Series on ASP.NET AJAX |
---|
Over the past several years web developers have started using JavaScript to make asynchronous postbacks to the web
server that only transmit and receive the necessary data; these techniques are commonly referred to as
AJAX.
Microsoft has released a free AJAX framework for ASP.NET developers named Microsoft ASP.NET AJAX.
This article series examines using Microsoft's ASP.NET AJAX framework to build responsive user interfaces.
|
Introduction
Microsoft's ASP.NET AJAX framework offers two models for developing interactive web applications: client-centric and server-centric. With the server-centric model, developers use the standard ASP.NET controls - the GridView, Buttons, TextBoxes, and so forth - but place them within an UpdatePanel control. The UpdatePanel control automatically converts normal postbacks to partial page postbacks and seamlessly updates the page's display with any modifications made by server-side code. On the other hand, with the client-centric model the developer is responsible for writing the JavaScript that performs any asynchronous requests to the server, as well as the script that updates the page on response.
The server-centric model is easier to use and more familiar to developers who have a solid background with ASP.NET controls, but who are not as comfortable with JavaScript and HTML. However, that ease of use comes at a cost: the server-centric model shuttles a substantial amount of data between the client and server on each partial page postback. In short, the UpdatePanel sends the page's view state to the server on a partial page postback and receives this (perhaps modified) view state back in response, regardless of whether the view state is needed to perform the server-side logic. Moreover, the entire rendered contents of the UpdatePanel are returned on response, even if only a small portion of the content in the UpdatePanel has been modified.
The client-centric model involves a bit more work than the server-centric model and a familiarity with HTML, JavaScript, and the Document Object Model (DOM). But using the client-centric model can greatly reduce the quantity of information exchanged between the client and server during a partial page postback. This article looks at one technique for retrieving server-side data in the client-centric model. Read on to learn more!
A Web Service Primer
Web Services are a mechanism by which two computers can interact over a network. Web Services are typically implemented using the client/server model, where a server exposes a Web Service which is then consumed by a client. For example, a weather website might provider a web service that returns current conditions for a particular city. A client application, be it a desktop application or another website, could call this web service passing along the city of interest. The weather website would respond by returning the current conditions for that city, which could then be displayed by the client application. In a nutshell, Web Services allow for machine-to-machine communication by using standardized transport and encoding protocols.
Most Web Services send data back and forth using SOAP, which is an XML-based protocol for encoding messages. For example, when a client application calls the weather Web Service it would do so by sending a message like the following to the Web Service's endpoint (e.g., the Web Service's URL, like www.weathersite.com/GetWeatherReport.asmx):
<soap:Envelope>
|
The Web Service would respond by sending the current conditions in San Diego, encoded in a SOAP message:
<soap:Envelope>
|
Creating and consuming Web Services in ASP.NET is easy because the .NET Framework handles all of the low-level, nitty-gritty work, such as generating, sending, receiving, and parsing the SOAP messages. To create a Web Service you just need to add a new Web Service file to your website project. This creates a class where you can define what methods are accessible via the Web Service. Likewise, when consuming a Web Service from a desktop or web application, you just point to the Web Service and Visual Studio automatically creates a proxy class, which has the same interface as the Web Service. To call the Web Service from the client application, simply call the corresponding method in the proxy class.
Calling Web Services from an ASP.NET AJAX Application
As noted in the Introduction, when developing ASP.NET AJAX applications using the client-centric model developers are responsible for writing the JavaScript that performs and asynchronous calls to the server and updates the page's display on response. One option for invoking server-side logic is to call a Web Service. But calling a Web Service from client-side script introduces two challenges:
- Web Services messages are usually encoded according to the SOAP protocol. However, AJAX applications typically prefer JSON, an alternate encoding standard better suited to JavaScript.
- When consuming a Web Service from a client application Visual Studio creates a proxy class on the client that mirrors the interface of the Web Service. However, when calling a Web Service from client-side JavaScript we need a JavaScript-based proxy class instead.
The second challenge is handled by the ScriptManager control. Recall that any page that uses the ASP.NET AJAX framework needs a ScriptManager control on the page. In the examples thus far in this series, we've simply added this control to the page and did nothing with it. However, you can reference any number of Web Services from the ScriptManager, which creates and exposes a JavaScript-based proxy class. As a result, you can invoke the Web Service from client-side script by using this proxy class, which means you don't need to write any code that serializes or deserializes messages, sends the message, and so on.
Creating a Web Service That Can Be Called from an ASP.NET AJAX Application
To illustrate calling a Web Service from an ASP.NET AJAX application, let's create a simple Web Service in our ASP.NET website and then build a page that calls this Web Service from JavaScript and displays the results on the page. (The code demonstrated in this article is available for download at the end of this article.) In particular, let's create a Web Service accepts two integers as input and returns their sum.
Start by adding a new Web Service to your ASP.NET website by right-clicking on the folder where you want the service's endpoint to exist, choosing
Add New Item, and then picking the Web Service template. Name this new Web Service NorthwindServices.asmx
. The code for the Web Service
is located in a separate file named NorthwindServices.asmx.vb
or NorthwindServices.asmx.cs
and is where we define the methods
for our Web Service. Create an Add
method by typing in the following code:
Imports System.Web
|
In order for this method to be accessible to an ASP.NET AJAX application we need to mark the service as being a "script service." To accomplish this
all we need to do is decorate the Web Service class with the System.Web.Script.Services.ScriptService
attribute. Simply add this attribute
before the Web Service class definition, like so:
<WebService(Namespace:="http://tempuri.org/")> _
|
With that additional attribute the NorthwindServices
Web Service can now accept JSON messages in addition to the standard SOAP messages.
Calling the Web Service from an ASP.NET AJAX Application
To call a Web Service from an ASP.NET AJAX application you first need to inform the ScriptManager control that you need a JavaScript-based proxy class for the service. This is accomplished by defining the path to the service in the ScriptManager control's
<Services>
section:
<asp:ScriptManager ID="ScriptManager1" runat="server">
|
This addition causes the ScriptManager to automatically generate a JavaScript proxy class and make it accessible to the page. To call the Web Service
from JavaScript you simply enter the fully qualified type of the Web Service (such as NorthwindServices
or, if you have placed the Web
Service in a namespace, then Namespace.NorthwindServices
), passing in any parameters. The proxy class calls the service asynchronously,
meaning that you need to provide a JavaScript function that will be called once the Web Service call completes. It is from this function that you'll update
the page's display to incorporate the information returned by the Web Service. (You can also specify a function to call if the Web Service call resulted
in an error.)
The demo available for download at the end of this article includes a page that uses the Web Service's Add
method. The page contains
two TextBox controls where the user can enter the numbers to sum. There's then a button that, when clicked, calls the Web Service from JavaScript and
displays the sum in a <span>
element named sum
. The markup for this user interface follows:
<asp:TextBox runat="server" ID="Num1" Columns="3"></asp:TextBox>
|
Note that the "Compute Sum" button is implemented as an <input type="button" />
rather than a Button Web control. This is because when
the button is clicked we want to run JavaScript code (instead of performing a postback). The button's client-side onclick
event handler
references a JavaScript function named ComputeSum
. The ComputeSum function calls the Web Service's Add
method, passing in the values
entered by the user in the Num1
and Num2
TextBox controls.
function ComputeSum() {
|
The JavaScript function document.getElementById(id)
function is used to grab the associated HTML element in the document. Because
the controls in question - Num1
and Num2
- are ASP.NET controls it is prudent to reference the value of the controls'
ClientID
properties rather than the literal ID
s, Num1
and Num2
. The reasoning behind this is because the controls'
ID
values may be modified at runtime if the TextBox appears within a naming container (such as a Master Page).
The call to the Add
method passes in four input paramters: the two integer inputs to sum plus a JavaScript function to execute when the
call completes (OnComputeSumSuccess
) and a JavaScript function to call if there is an error (OnComputeSumError
). These code
for these two functions follows:
function OnComputeSumSuccess(results) {
|
The OnComputeSumSuccess
references the sum
span and sets its innerHTML
property to the result returned.
The OnComputeSumError
function displays the error message in a modal dialog box.
The following screen shots show this functionality in action. When the page is first visited the user interface includes the two textboxes and a "Compute Sum" button.

After entering some values, such as 4 and 7, and clicking the "Compute Sum" button, the client-side ComputeSum
function runs and sends
an HTTP request to the NorthwindServices.asmx
Web Service with the following contents:
{"x":"4","y":"7"}
|
The above JSON is received by the Web Service and deserialized into the input parameter values of 4 and 7, and the Add
method is invoked with those
values. It computes the sum - 11 - and returns the results back to the client as follows:
{"d":11}
|
Upon receiving the response, the
To appreciate the savings in data afforded by the client-centric model I created two pages with identical functionality, but with one that uses the
client-centric model and the other using the server-centric model. Specifically, the page displays the proucts in the Northwind database in a GridView
and includes a "Quick Summary Report" user interface that lets the visitor run one of three different queries:
The page that implements the server-centric approach uses two UpdatePanels - one for the "Quick Summary Report" section and one for the GridView.
Moreover, the two have their
Clicking the "Reveal Answer" button in the page that implements the server-centric model causes a partial page postback and executes the Button's
The bulk of that data comes from the view state (which I've pared down in the snippet above). And the server responds with over 3,500 bytes of data, which includes
the entire markup for the region in the UpdatePanel (even though only the Label's
That's a lot of needless information being shuttled between the client and the server. This is the cost of enjoying the ease of use of the server-centric
model.
The demo for download at the end of this article includes both server-centric model (discussed above) and a client-centric model implementations. The
client-centric model implementation uses calls a Web Service to determine how many products meet the specified criteria and in doing so drastically
reduces the overall traffic. First of all, only the necessary information is sent from the client to the server, namely the operation to perform and
the cost entered by the user in the textbox. Doing a search for products that cost more than $5.00 results in a request that consumes a mere 43 bytes
(instead of over 2,400, as in the server-centric model implementation).
And the response was reduced from over 3,500 bytes down to 8 bytes!
Granted, using the client-centric model puts us "closer to the metal" - we have to write more HTML and more JavaScript - but it grants you more control over the
interactions between the client and server and provides a way to minimize the amount of data being exchanged, thereby resulting in a more responsive
web application.
Happy Programming!
OnComputeSumSuccess
method is called, passing in the value 11 as the return parameter. This value is
then displayed as the contents of the <span>
element.
Comparing the Traffic Sent by the Server-Centric and Client-Centric Models
The client-centric model certainly requires more effort to implement than the server-centric model. To implement the Add functionality in a
server-centric model we'd make turn the "Compute Sum" button and sum <span>
element into a Button Web control and Label Web control,
respectively, place these controls in an UpdatePanel, and create a Click
event handler for the button, where we'd sum the two numbers and display
their output in the Label. But the advantage of the client-centric model is that you have much finer control over the information exchanged between
the client and server. Moreover, the sheer quantity of information is usually significantly less.
Where what operation to perform is chosen from a drop-down list and the value of X is entered via a textbox (see the screen shot below).
UpdateMode
properties set to Conditional
, ensuring that when one UpdatePanel causes a partial
page postback that the other UpdatePanel is not involved in the process. Still, the entire view state is sent back and forth regardless of what UpdatePanel
causes a partial page postback, and that view state contains information about controls in both UpdatePanels.
Click
event handler. This event handler determines the number of products that meet the specified criteria and then updates the Label control
to the right of the Button with the results. Clearly, the only information that needs to be transmitted between the client and server is the
selected operation, the dollar amount, and the resulting number of products that apply to that query. However, the server-centric model passes much more
information back and forth. On the partial postback over 2,400 bytes of data are sent to the server. (Note: you can use a tool like
Fiddler to examine the information sent during a partial page postback; see
Troubleshooting Website Problems by Examining the HTTP Traffic for more information
on how to use this free tool.)
ScriptManager1=QuickSummaryUpdatePanel%7CRevealAnswer&__EVENTTARGET=&__EVENTARGUMENT=
&__VIEWSTATE=%2FwEPDwULL...&Operation=CostMore&QueryCost=5.00
&AllProducts%24ctl02%24ctl00=on&AllProducts%24ctl11%24ctl00=on
&__ASYNCPOST=true&RevealAnswer=Reveal%20Answer!
Text
property has changed) along with the entire view state.
930|updatePanel|QuickSummaryUpdatePanel|
<p>
<b>Quick Summary Report:</b>
<br />
How many products
<select name="Operation" id="Operation">
<option selected="selected" value="CostMore">Cost More Than</option>
<option value="CostLess">Cost Less Than</option>
<option value="CostExact">Cost Exactly</option>
</select>
$<input name="QueryCost" type="text" value="5.00" size="8" id="QueryCost" style="text-align: right;" />?
</p>
<p>
<input type="submit" name="RevealAnswer" value="Reveal Answer!" id="RevealAnswer" />
<span id="QueryAnswer" style="background-color:Yellow;font-size:Large;font-weight:bold;">The answer to your query: 75 products!</span>
</p>
|0|hiddenField|__EVENTTARGET||0|hiddenField|__EVENTARGUMENT||1904|hiddenField|__VIEWSTATE|/wePDwU...
{"operation":"CostMore","queryCost":"5.00"}
{"d":75}
To See Script-Enabled Web Services in Action...
To see an example of script-enabled Web services in action be sure to read Periodically Updating
the Screen and Web Page Title with ASP.NET AJAX, which shows how to use script-enabled Web services and a touch of JavaScript to
interactively update a web page to show information specific to the currently logged on user!
Attachments:
Further Reading
A Multipart Series on ASP.NET AJAX
Over the past several years web developers have started using JavaScript to make asynchronous postbacks to the web
server that only transmit and receive the necessary data; these techniques are commonly referred to as
AJAX.
Microsoft has released a free AJAX framework for ASP.NET developers named Microsoft ASP.NET AJAX.
This article series examines using Microsoft's ASP.NET AJAX framework to build responsive user interfaces.