Professional Documents
Culture Documents
ASP NET AJAX For Developers
ASP NET AJAX For Developers
NET AJAX
for Developers
Information in this document is subject to change without notice. The example companies,
organizations, products, people, and events depicted herein are fictitious. No association with
any real company, organization, product, person or event is intended or should be inferred.
Complying with all applicable copyright laws is the responsibility of the user. Without limiting
the rights under copyright, no part of this document may be reproduced, stored in or
introduced into a retrieval system, or transmitted in any form or by any means (electronic,
mechanical, photocopying, recording, or otherwise), or for any purpose, without the express
written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarked, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you
any license to these patents, trademarks, copyrights, or other intellectual property.
Microsoft, MS-DOS, MS, Windows, Windows NT, MSDN, Active Directory, BizTalk, SQL Server,
SharePoint, Outlook, PowerPoint, FrontPage, Visual Basic, Visual C++, Visual J++, Visual
InterDev, Visual SourceSafe, Visual C#, Visual J#, and Visual Studio are either registered
trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries.
Other product and company names herein may be the trademarks of their respective owners.
Table of Contents
ASP.NET AJAX abstracts the mechanics of AJAX so developers can build AJAX-enabled
applications without having to become experts in JavaScript, XML-HTTP, and other
technologies that make up AJAX itself. For example, ASP.NET AJAX includes an
UpdatePanel control that enables selected regions of a Web page to be updated via
AJAX. Simply adding an UpdatePanel control to a page can often replace tens of hours
of tedious coding involving JavaScript, browser Document Object Models (DOMs), and
XmlHttpRequest objects. Similar abstractions reduce the complexity of other tasks—
adding animations, popup panels, drag-and-drop support, and more—to little more
than declaring controls in a Web page.
AJAX stands for Asynchronous JavaScript and XML. “Asynchronous” alludes to the
asynchronous calls (or “callbacks”) that AJAX browser clients make to Web servers to
submit (and often to retrieve) data. Callbacks are launched by JavaScript executing in
the browser, and when a callback completes, JavaScript is used to process the results.
The chief benefit to performing callbacks asynchronously is that it frees the browser
to execute code and continue responding to user input while waiting for callbacks to
complete.
The “XML” in “Asynchronous JavaScript and XML” alludes to the protocol used by
asynchronous callbacks (XML-HTTP) and to the browser object used to execute XML-
HTTP requests (XmlHttpRequest). AJAX applications sometimes use XML to serialize
data transmitted over the wire, but inceasingly, JSON—short for JavaScript Object
Notation—is the serialization format of choice. JSON is more compact than XML, is
more readable to the human eye, and typically requires less time and processing
power to decode. For these reasons, it’s the native serialization format employed by
ASP.NET AJAX. You can read all about JSON at http://www.json.org/.
In the words of the creator of the term AJAX, “Ajax isn’t a technology. It’s really
several technologies, each flourishing in its own right, coming together in powerful
new ways.” Indeed, the two technologies that form the foundation for all AJAX
applications—JavaScript and XmlHttpRequest—predate AJAX by many years.
Today AJAX is employed by numerous Web applications to make browsing the Web a
richer and more pleasing experience. Examples or popular Web applications that use
AJAX include Windows Live Local, Outlook Web Access, Gmail, Google Suggests, and
Google Earth. In all likelihood, the popularity of AJAX will only increase in coming
years and drive the demand for AJAX frameworks such as ASP.NET AJAX.
• When a postback occurs, the browser discards the HTML it’s holding and
redraws the page using the HTML returned in the HTTP response. Consequently,
the entire page “flashes” even if only a fraction of the page actually needed to
be redrawn.
• When a postback occurs, all of the form input on the page—including ASP.NET
view state and other data stored in hidden input fields—is transmitted to the
server, even if only a fraction of that input is actually used.
• The browser no longer discards the HTML it’s holding, eliminating the flashing
and vastly improving the user experience.
• Rather than transmit all form input to the server, an asychronous callback can
transmit just the input that’s needed, leading to better and more efficient
bandwidth utilization.
Figure 1-1 demonstrates how replacing postbacks with callbacks improves the user
experience. The browser first submits a conventional HTTP GET request to fetch HTML
content from a Web server. The browser renders the content to display the Web page.
When the user clicks a button on the page, what would normally be a postback in an
ASP.NET page is instead an asynchronous callback thanks to a bit of JavaScript wired
to the button. The callback travels to the server in the form of an asynchronous XML-
HTTP request. Significantly, the browser doesn’t discard the HTML it’s displaying, so
until the callback completes, the page remains unchanged in the browser.
if (window.XMLHttpRequest)
{
xhr = new XMLHttpRequest(); // IE 7, Firefox, etc.
}
else // Older IE browsers
{
try
{
xhr = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (ex)
{
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
}
The next step is to launch the callback itself. That’s accomplished by opening the
XmlHttpRequest object (and in the process providing key information such as the URL
targeted by the XML-HTTP request) and calling its send method. The “true” passed in
the third parameter specifies that the request should be submitted asynchronously
rather than synchronously:
...
function checkForCompletion()
{
if (xhr.readyState == 4 && xhr.status == 200)
{
window.alert(xhr.responseText);
}
}
Because the call is asynchronous, send returns immediately. In this example, the
checkForCompletion function is called each time the XmlHttpRequest object’s ready
state changes. A readyState property equal to 4 indicates that the asynchronous
request has completed, and a status code of 200 indicates it completed successfully.
This example uses window.alert to display the response returned by the callback,
which is accessed through the XmlHttpRequest object’s responseText property. (If the
response contains an XML document rather than raw text, responseXML can be used
instead.) In real life, JavaScript code of greater complexity is typically provided to do
something more tangible with the response—for example, to update content on the
page.
Writing AJAX code without the benefit of an AJAX framework can be tedious and time-
consuming due to differences between browsers and the need to write JavaScript code
to process the results of XML-HTTP requests. AJAX frameworks such as ASP.NET AJAX
simplify the development process by encapsulating and abstracting key aspects of
AJAX itself, and even by abstracting the differences between browsers.
The ASP.NET 2.0 AJAX Extensions are the server half of ASP.NET AJAX. A schematic
appears in Figure 1-2. The box labeled “AJAX Server Controls” represents controls such
as UpdatePanel and UpdateProgress, which provide easy-to-use wrappers around AJAX.
The application services bridge is a set of Web services that expose key ASP.NET 2.0
services such as membership and profiles to browser clients. The asynchronous
communications layer permits ASMX Web methods and special ASPX methods known as
page methods to serve as endpoints for AJAX callbacks. It also enhances ASP.NET 2.0
with support for JSON serialization and deserialization. The ASP.NET 2.0 AJAX
Extensions are described more fully in Section 2.0.
• AJAX server controls make it extremely easy to add AJAX support to ASP.NET
Web pages. Simply declare a control on the page and the control does the rest.
• AJAX server controls require ASP.NET on the server. They emit code (and
sometimes markup) that leverages the Microsoft AJAX Library on the client.
The ASP.NET AJAX 1.0 download contains the core features of the platform, including
the UpdatePanel server control and the browser compatibility layer and asynchronous
communications layer on the client. These features are fully tested and fully
supported by Microsoft.
The ASP.NET AJAX Control Toolkit adds several additional server controls to the
package as well as a software development kit (SDK) for developing controls of your
own. The ASP.NET AJAX Control Toolkit is a shared-source, community-supported
project. It is fully tested, vetted by the community, and considered robust enough for
use on production servers. It’s hosted at CodePlex (http://www.codeplex.com/) and is
constantly being updated with new controls and code samples.
The ASP.NET AJAX Futures CTP further expands the feature set and provides a
mechanism for Microsoft to deliver new features and collect feedback on those
features. CTP stands for “Community Technology Preview” and is the term used to
describe features that are still under development. Conservative shops that prefer to
use only fully tested, fully supported features of the platform can do so by installing
only the core ASP.NET AJAX download (and optionally the control toolkit). More agile
shops that want to leverage ASP.NET AJAX to the fullest can install the Futures CTP
and enjoy access to a wider range of features. Figure 1-4 documents the division of
features between core and CTP.
Server
ASP.NET AJAX
Feature ASP.NET AJAX January 2007
Futures CTP
Asynchronous client-to-server networking ●
ScriptManager and ScriptManagerProxy controls ●
UpdatePanel control ●
UpdateProgress control ●
Timer control ●
Application services bridge ●
Page methods ●
DragOverlayExtender control ●
ProfileService control ●
Client
ASP.NET AJAX
Feature ASP.NET AJAX January 2007
Futures CTP
JavaScript type extensions ●
JavaScript type system ●
JSON serialization and deserialization ●
Client-side application services bridge ●
Calling Web services from JavaScript ●
Debugging aids ●
HTML controls (Button, CheckBox, Label, etc.) ●
Data controls (ListView, ItemView, etc.) ●
Validation controls ●
Drag-and-drop support ●
Animation support ●
xml-script support ●
The fourth download—the Microsoft AJAX Library—contains the JavaScript files that
make up the Microsoft AJAX Library. Developers building applications for non-ASP.NET
platforms can use these files to enjoy all the benefits of ASP.NET AJAX in browser
clients—without the need for ASP.NET on the server.
2.0 The ASP.NET 2.0 AJAX Extensions
The ASP.NET 2.0 AJAX Extensions extend ASP.NET 2.0 with new controls, features, and
capabilities, including the ability to use ASMX Web methods and ASPX page methods as
endpoints for asynchronous XML-HTTP requests and support for JSON serialization and
deserialization. They also include built-in Web services that enable the ASP.NET 2.0
membership and profile services to be accessed by JavaScript clients.
Core features of the ASP.NET 2.0 AJAX Extensions are contained in the assembly
System.Web.Extensions.dll, which is added to the Global Assembly Cache (GAC) when
ASP.NET AJAX is installed. The ASP.NET AJAX Control Toolkit is packaged in a separate
assembly named AjaxControlToolkit.dll, while the Futures CTP lives in
Microsoft.Web.Preview.dll. AjaxControlToolkit.dll and Microsoft.Web.Preview.dll are
not installed in the GAC; instead, they’re privately deployed in the Bin subdirectory.
The sections that follow introduce the ASP.NET 2.0 AJAX Extensions and offer a guided
tour of its features.
The AJAX server controls supplement the server controls built into ASP.NET (TextBox,
Panel, TreeView, and so on) and conform to the same programming model and usage
patterns. In Visual Studio, AJAX server controls can be dragged from the Toolbox and
dropped onto a page to add AJAX capabilities to that page. Figure 2-1 lists the core
AJAX server controls included in ASP.NET AJAX 1.0.
Control Description
ScriptManager Enables ASP.NET AJAX to be used in a Web page.
ScriptManagerProxy Enables content pages to add script references and
service references to a ScriptManager control declared in
a master page.
UpdatePanel Implements partial-page rendering in a Web page.
UpdateProgress Displays a custom user interface (UI) while updates are
pending in UpdatePanel controls.
Timer Implements a programmable callback timer.
The following sections provide a brief overview of these controls. The goal isn’t to
provide an exhaustive reference, but to provide helpful information regarding the
controls’ capabilities and syntactical help using them.
2.1.1 ScriptManager and ScriptManagerProxy
Every ASP.NET AJAX page begins with a ScriptManager control. The ScriptManager
control’s primary duties include:
ScriptManager controls also provide script registration methods (so custom controls
that emit JavaScript can be compatible with UpdatePanel controls), allow localization
features to be enabled and disabled, control whether the debug or release version of
the Microsoft AJAX Library is downloaded, and more.
A page that uses ASP.NET AJAX must contain one—and only one—ScriptManager
control. The declaration can be as simple as this:
Figure 2-2 offers a more comprehensive look at the ScriptManager schema. The
<Services> element declares Web service references, enabling those Web services to
be called through JavaScript proxies (Section 2.4). The <Scripts> element enables a
page to download JavaScript files that aren’t downloaded by default. For example,
the following ScriptManager declaration downloads PreviewScript.js, which contains
many of the Microsoft AJAX Library features found in the ASP.NET AJAX Futures CTP,
as well as a custom JavaScript file named UIMap.js:
The ScriptManager control’s Error properties provide control over error handling. By
default, if an exception is thrown during an asynchronous ASP.NET AJAX callback, the
custom error page registered in the <customErrors> section of Web.config is displayed.
If no custom error page is designated, then ASP.NET AJAX displays the exception’s
Message property in an alert window on the client. You can set the
AllowCustomErrorRedirect property to false to prevent custom error pages from being
shown, and use the AsyncPostBackErrorMessage property to override the default error
message with a custom one. Additionally, you can use the OnAsyncPostBackError event
to execute a handler on the server if an exception occurs during an asynchronous
callback. From the handler, you can specify the error message returned to the client.
Figure 2-4 illustrates how UpdatePanel controls perform partial-page rendering, and
why partial-page rendering eliminates the excessive flashing that characterizes many
ASP.NET Web pages. In a traditional update, the page posts back to the server. The
browser erases the page and redraws it using the content returned in the response. A
page with an UpdatePanel control works differently. The UpdatePanel automatically
converts postbacks from controls inside it into asynchronous XML-HTTP callbacks. The
browser doesn’t erase the page, and when the callback completes, the UpdatePanel
control updates its content using JavaScript. Thus, less rendering is performed on the
server (only controls inside the UpdatePanel undergo a rendering cycle), less data
comes back in the response, and the user experience is improved because the page
doesn’t flash.
The UpdatePanel control also supports explicitly defined triggers. Triggers come in
two varieties. The AsyncPostBackTrigger allows controls outside an UpdatePanel to
trigger updates of the UpdatePanel’s content. Under the hood, AsyncPostBackTrigger
converts postbacks generated by the specified controls into asynchronous callbacks.
The other trigger type, PostBackTrigger, allows controls inside an UpdatePanel to post
back rather than call back. In Figure 2-6, the UpdatePanel control converts postbacks
from all the controls declared inside it and postbacks generated by a Button control
outside the UpdatePanel into asynchronous callbacks that refresh the UpdatePanel:
Figure 2-6: UpdatePanel triggers
<asp:Button ID="Button1" Text="Click Me"
OnClick="Button1_Clicked" runat="" />
...
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Button1"
EventName="Click" />
</Triggers>
<ContentTemplate>
<!-- Declare content here -->
</ContentTemplate>
</asp:UpdatePanel>
In order for an UpdatePanel control to work, the page that hosts it must also contain a
ScriptManager control. In addition, the ScriptManager control must be configured to
enable partial-page rendering, as shown here:
Most controls can be hosted inside an UpdatePanel, but some cannot. In particular,
controls that emit JavaScript of their own cause myriad problems with UpdatePanel
controls unless they use RegisterClientScriptBlock, RegisterStartupScript, and other
ScriptManager registration methods to register the script they return. For more
information on script registration and how to build custom controls that are
compatible with the UpdatePanel control, read the post entitled “HOWTO: Write
controls compatible with UpdatePanel without linking to the ASP.NET AJAX DLL” by
Eilon Lipton, lead developer of the UpdatePanel control, at
http://forums.asp.net/thread/1445844.aspx.
The UpdatePanel control does have one drawback: its callbacks aren’t as efficient on
the wire as hand-coded AJAX callbacks. The data transmitted to the server includes
view state and other form input and is in fact almost identical to what’s transmitted in
a traditional postback. The response includes all the freshly rendered content. The
size of that content is roughly proportional to the size of the UpdatePanel control’s
<ContentTemplate>. In other words, if the UpdatePanel control encompasses half the
page, then the response size is roughly half that generated by a traditional postback.
UpdatePanel callbacks aren’t as efficient as hand-coded AJAX callbacks once they
reach the server, either, because the page undergoes a nearly complete life cycle.
Techniques exist for optimizing UpdatePanel usage and even replacing UpdatePanel
controls with Web services and JavaScript, but those techniques are beyond the scope
of this document. Suffice it to say that UpdatePanel controls emphasize ease-of-use
over efficiency—proof once more that there’s no such thing as a free lunch.
2.1.3 UpdateProgress
The UpdateProgress control is a companion to the UpdatePanel control. It enables
pages that host UpdatePanel controls to display special content elements when an
update is in progress—for example, an animated GIF depicting a progress bar or a clock
with spinning hands. It can also be used to display UIs for canceling updates that
haven’t completed.
<script type="text/javascript">
function cancelUpdate()
{
var obj = Sys.WebForms.PageRequestManager.getInstance();
if (obj.get_isInAsyncPostBack())
obj.abortPostBack();
}
</script>
By default, if a page contains just one UpdateProgress control, the control displays its
content when any UpdatePanel control on the page updates. However, you can
declare multiple UpdateProgress controls on a page and associate each with a specific
UpdatePanel using the UpdateProgress control’s AssociatedUpdatePanelID property.
This is useful when a page contains multiple UpdatePanel controls and you want to
display a different progress UI for each one.
Control Description
Accordion Displays “accordion” UI consisting of multiple
panes, only one of which is visible at a time.
AlwaysVisibleControlExtender Pins controls in a specified position as the page
is scrolled or resized.
AnimationExtender Adds animation effects to Web pages.
AutoCompleteExtender Adds context-sensitive drop-down completion
lists to TextBox controls.
Calendar Adds popup calendars to date-entry TextBox
controls.
CascadingDropDown Connects DropDownList controls so that a
change to one updates content in the others.
CollapsiblePanelExtender Implements content panels that can be
interactively expanded and collapsed.
ConfirmButtonExtender Enhances button controls with popup
confirmation boxes.
DragPanelExtender Enables Panel controls to be interactively
dragged and repositioned.
DropDownExtender Adds SharePoint-style drop-down menus to
other controls.
DropShaow Adds drop shadows to Panel controls.
DynamicPopulateExtender Populates controls by calling Web methods or
page methods asynchronously.
FilteredTextBoxExtender Filters input to TextBox controls.
HoverMenuExtender Adds popup “hover” menus to other controls.
MaskedEditExtender Adds visual formatting cues to TextBox
controls.
ModalPopupExtender Displays content modally.
MutuallyExclusiveCheckBoxExtender Groups CheckBox controls and ensures that
only one member of the group is checked.
NoBot Uses challenge-response mechanism to filter
out “bot” input without user intervention.
NumericUpDownExtender Adds up-down buttons to TextBox controls.
PagingBulletedListExtender Adds sorting and paging to BulletedList
controls.
PasswordStrength Enhances password-entry TextBox controls with
visible indication of password strength.
PopupControlExtender Attaches popup content to other controls.
Rating Displays interactive rating UI.
ReorderList Implements lists whose items can be reordered
by the user.
ResizableControlExtender Allows content to be resized interactively.
RoundedCornersExtender Adds rounded corners to existing elements.
SliderExtender Adds sliders to TextBox controls.
TabContainer and TabPanel Implements interactive tabbed UI.
TextBoxWatermarkExtender Adds watermark text to TextBox controls.
ToggleButtonExtender Enhances CheckBox controls with images that
toggle between checked and unchecked mode.
UpdatePanelAnimationExtender Plays animations when UpdatePanel controls
update.
ValidatorCalloutExtender Adds popup UIs to ASP.NET validator controls.
One of the most compelling controls in the ASP.NET AJAX Control Toolkit is the
AutoCompleteExtender control, which adds context-sensitive drop-down completion
lists to TextBox controls (see Figure 2-10). As the user types, the list is updated, and
at any time the user can stop typing and simply choose an item from the list. Items in
the list come from a Web service, and it is the developer’s responsibility to provide
that Web service. AutoCompleteExtender does the rest, automatically calling the Web
service each time the text in the TextBox changes and passing as input what the user
has typed thus far.
Figure 2-11 shows how AutoCompleteExtender controls are declared in Web pages.
The TargetControlID property identifies the TextBox that the AutoCompleteExtender
control extends, while ServicePath and ServiceMethod identify the Web service and
Web method that are called on each keystroke to generate a context-sensitive
completion list. (The Web service is a conventional ASMX Web service tagged with the
ScriptService attribute described in Section 2.4.) MinimumPrefixLength=”2” instructs
the AutoCompleteExtender to make the first call to the Web service after two
characters have been typed, and CompletionSetCount=”20” tells it to display up to 20
items in the completion list. If desired, you can also use the CompletionListElementID
property to identify an ASP.NET Panel control that acts as a proxy for the completion
list. Explicitly declaring the completion list in this way is useful for styling it using
control properties or CSS.
The Web method called to generate the completion list can have any name you want,
but it must have the following signature:
public string[] GetMatchingZipCodes(string prefixText,
int count);
When the method is called, prefixText specifies the text currently displayed in the
TextBox, and count specifies the maximum number of strings to return in the string
array. The strings returned by the method are used to populate the completion list.
The markup in Figure 2-12 declares an Image control and converts it into a floatable
image with a DragOverlayExtender control. The TargetControlID property identifies
the Image. DragOverlayExtender can be applied to Panels, Images, and a variety of
other control types, but it cannot be used with controls that generate HTML <input>,
<button>, <select>, <textarea>, or <label> elements. You can’t, for example, apply a
DragOverlayExtender control to a TextBox control.
To make an ASMX Web service accessible from ASP.NET AJAX clients, you first
attribute the Web service class with a System.Web.Script.Services.ScriptService
attribute. (This attribute can be applied in lieu of or in addition to the traditional
WebService attribute.) Figure 2-12 shows the C# code-behind class for a simple Web
service whose lone Web method is callable from JavaScript.
Figure 2-12: Code-behind class for a Web service that’s callable from JavaScript
[System.Web.Script.Services.ScriptService]
public class ZipCodeService : System.Web.Services.WebService
{
[WebMethod]
public string[] GetCityAndState(string zip)
{
...
}
}
The next step is to add a service reference. The service reference identifies the Web
service by URL and downloads a JavaScript proxy through which the Web service can
be called. Service references can be created declaratively using the <Services>
element of a ScriptManager or ScriptManagerProxy control, as shown in Figure 2-13.
The JavaScript proxy generated by the service reference has the same name as the
Web service class. Figure 2-14 demonstrates how an ASP.NET AJAX client can call the
GetCityAndState method shown in Figure 2-12 to convert a ZIP code into a city and
state. The call is asynchronous, so the parameter list on the client always contains at
least one more parameter than the parameter list on the server. The extra parameter
is the name of the JavaScript function that’s called when the asynchronous callback
completes.
Figure 2-14: Calling the GetCityAndState method from JavaScript
ZipCodeService.GetCityAndState("98052", onComplete);
...
function onComplete (result)
{
window.alert(result);
}
In practice, you’ll probably want to know if the callback fails so you can respond
gracefully. Figure 2-15 demonstrates how to call GetCityAndState and specify a
JavaScript function (onFailed) that’s called if the call fails—for example, if an
exception is thrown on the server or the call times out.
In traditional ASP.NET applications, Web service calls use XML and SOAP. Calls to Web
services from ASP.NET AJAX clients are very different. By default, data is encoded in
JSON (more on this in Section 2.6), and the packet format is a custom one that is much
lighter-weight than SOAP. Moreover, none of the view state and other form input that
travels to the server in a normal ASP.NET postback is transmitted. The net result is
maximum efficiency on the wire and little wasted motion on either the client or
server.
Figure 2-16 shows the request and response packets generated when the
GetCityAndState method is called through a JavaScript proxy generated by ASP.NET
AJAX. The actual payload—the request and response bodies—contain JSON-encoded
input and output and nothing more. Clearly, calling ASMX endpoints from ASP.NET
AJAX clients is both lightweight and efficient.
When you declare a service reference like the one in Figure 2-13, the ScriptManager
control emits the following markup:
The browser submits an HTTP request for ZipCodeService.asmx/js, and the server
responds by returning a JavaScript proxy. (You can see the proxy by manually
submitting the same request yourself, or by including an InlineScript=”true” attribute
in the <asp:ServiceReference> tag and then examining the resulting source code in
your browser.)
How does the server know how to handle an ASMX request with a “/js” at the end?
Because of the following statements in the <httpHandlers> section of the Web.config
file of an ASP.NET AJAX Web site, which map all requests for ASMX resources to an
ASP.NET 2.0 AJAX Extensions class named ScriptHandlerFactory:
<remove verb="*" path="*.asmx"/>
<add verb="*" path="*.asmx" validate="false"
type="System.Web.Script.Services.ScriptHandlerFactory, ..."
/>
/AtlasRC/ZipCodeService.asmx/GetCityAndState
When a client places a call to a Web method through a JavaScript proxy, the proxy
appends the method name to the URL. The request is ultimately processed by the
RestHandler class, which deserializes the input parameters, invokes the Web method,
and returns the serialized output to the caller.
Although ASP.NET AJAX currently supports only ASMX Web services, support could be
added for other Web service platforms by extending those platforms to support the
same special URL semantics as ScriptHandlerFactory and friends.
2.4.2 The ScriptMethod Attribute
The GetCityAndState method in Figure 2-12 is decorated with the WebMethod
attribute used in virtually all ASMX Web services. Web methods called from JavaScript
can alternatively be marked with the ASP.NET 2.0 AJAX Extensions’
System.Web.Script.Services.ScriptMethod attribute, which provides added control
over the format of the data that passes over the wire. Key properties of the attribute
include:
The ResponseFormat property is particularly useful for serializing data types that
aren’t compatible with JSON into XML, and with methods that return XML data. The
following Web method uses a ScriptMethod attribute to prevent an XmlDocument from
being serialized into JSON:
[ScriptMethod (ResponseFormat=ResponseFormat.Xml)]
public XmlDocument GetData()
{
...
}
Of course, the XML must be parsed on the client to extract data from it.
Page methods must be public static methods and must be decorated with the
WebMethod or ScriptMethod attribute. (The latter performs the same function for
page methods as it does for Web methods.) Figure 2-18 shows the C# code-behind class
for a page that implements the GetCityAndState method from Figure 2-12 as a page
method rather than as an ASMX Web method.
On the client, page methods are called from JavaScript through the special
PageMethods proxy, as shown in Figure 2-19. Page methods don’t require service
references as Web services do. That is, you don’t need to declare a service reference
in a ScriptManager (or ScriptManagerProxy) control to facilitate calls to page methods.
You do, however, have to enable page methods by setting a ScriptManager control’s
EnablePageMethods property to true:
Under the hood, page methods offer the same efficiency as Web methods. View state
and other input is not transmitted to the server when page methods are called, and
because page methods are static, the ASP.NET 2.0 AJAX Extensions can call them
without instantiating a page object. A call to a page method does not invoke the page
life cycle that is triggered by conventional ASP.NET requests.
2.6 JSON
ASP.NET AJAX clients that call Web methods and page methods aren’t limited to
passing strings and other primitive data types; they can pass complex data types, too.
By default, ASP.NET AJAX serializes data passed to and from Web methods and page
methods using the industry-standard JavaScript Object Notation (JSON) format. JSON
is a lightweight data interchange format whose syntax is based on JavaScript itself. It
is less verbose than XML (leading to greater efficiency on the wire) and easier to parse
and deserialize, thanks in part to the JavaScript eval function. In an ASP.NET AJAX
client, JSON support is provided by the Sys.Serialization.JavaScriptSerializer class. On
the server, it’s provided by the System.Web.Script.Serialization.JavaScriptSerializer
class.
Suppose a Web method or page method returns a Point object—an instance of the .NET
Framework’s System.Drawing.Point type. Under the hood, the ASP.NET 2.0 AJAX
Extensions call JavaScriptSerializer.Serialize to serialize the Point object. If the
object’s X and Y properties are initialized to 100 and 200, respectively, here’s the
JSON representation of the object passed over the wire to the caller:
{"IsEmpty":false,"X":100,"Y":200}
Had the Point object been serialized with the .NET Framework’s XML serializer
instead, it would have been serialized this way:
<?xml version="1.0"?>
<Point xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<X>100</X>
<Y>200</Y>
</Point>
On the client, the JSON-serialized Point object can be handled this way:
WebServiceName.GetPoint(onComplete);
...
function onComplete(result)
{
// Displays "100, 200"
window.alert(result.X + ', ' + result.Y);
}
Not all types are JSON-compatible. JSON does not, for example, include provisions for
handling circular references. When you need to return complex data types that aren’t
JSON-compatible, you can use the ScriptMethod attribute with the response format
set to ResponseFormat.Xml to serialize the types into XML as described in Section
2.4.2. Alternatively, you can build and register custom JSON converters that allow
types that aren’t normally JSON-compatible to be serialized and deserialized. The
ASP.NET AJAX January Futures CTP contains three such converters: one for DataSets,
one for DataTables, and one for DataRows.
ASP.NET AJAX’s JSON serializers provide special handling for one common .NET data
type that isn’t handled natively by JSON: System.DateTime. The serialization format
used is specific to .NET and would require special handling to be used on other
platforms.
2.7.1 AuthenticationService
Sys.Services.AuthenticationService, which is an instance of the
Sys.Services._AuthenticationService class defined in the Microsoft AJAX Library, is the
client-side proxy for the ASP.NET 2.0 membership service.
Sys.Services.AuthenticationService methods enable JavaScript clients to log users in
and out (login and logout) and determine whether they’re currently logged in
(get_isLoggedIn) by invoking the membership service on the server. The JavaScript
code in Figure 2-20 attempts to log in a user by passing a user name and password.
The result parameter passed to onLoginCompleted indicates whether the login
succeeded (that is, whether the supplied credentials were valid and the user is
currently permitted to log in). If the call itself fails (rather than the login),
onLoginFailed is called instead.
In order for this to work, the authentication mode must be set to “Forms” on the
server. In addition, the ASP.NET AJAX Web service that front-ends the membership
service on the server must be enabled. (It is disabled by default). The following
configuration section enables the Web service:
<microsoft.web>
<scripting>
<webServices>
<authenticationService enabled="true" />
</webServices>
</scripting>
</microsoft.web>
2.7.2 ProfileService
A separate JavaScript proxy named Sys.Services.ProfileService (an instance of the
Sys.Services._ProfileService class defined in the Microsoft AJAX Library) provides a
client-side interface to the ASP.NET 2.0 profile service. It enables JavaScript clients to
use the profile service to store per-user data persistently. One use for this feature is
to store personalization data in back-end databases on the server (as opposed to
storing it in cookies, for example).
Profile properties must be defined on the server before they can be accessed from the
client. The following configuration section defines a profile containing a single string-
type property named ScreenName:
<system.web>
<profile>
<properties>
<add name="ScreenName" />
</properties>
</profile>
</system.web>
Like the authentication Web service, the profile Web service must be enabled before
it can be used. The following example shows how to enable it and expose the
ScreenName property to the client:
<microsoft.web>
<scripting>
<webServices>
<profileService enabled="true"
readAccessProperties="ScreenName"
writeAccessProperties="ScreenName"
/>
</webServices>
</scripting>
</microsoft.web>
The Microsoft AJAX Library is independent of server platforms. It can be used with or
without the ASP.NET 2.0 AJAX Extensions, and developers can easily build pages in
PHP, ColdFusion, and other languages that emit JavaScript code that leverages the
Microsoft AJAX Library—just as pages built with the ASP.NET 2.0 AJAX Extensions do.
The Microsoft AJAX Library is physically packaged in the JavaScript files listed in
Figure 3-1. The files come in both debug and release versions. The release versions are
stripped down to the bare essentials (even white space is removed) to minimize
download size. ASP.NET developers use ScriptManager and ScriptManagerProxy
controls to download these files to the client. However, developers who want to use
the Microsoft AJAX Library with other platforms can use <script> elements to download
the files.
The Microsoft AJAX Library is factored into individual files for download granularity. By
default, MicrosoftAjax.js is the only file downloaded. The uncompressed size of the
release version is 79K, and after the file is GZIPped, the size drops to approximately
15K on the wire. Pages that use UpdatePanel controls also download
MicrosoftAjaxWebForms.js, which adds another 5K or so to the compressed download.
Browsers cache JavaScript files, so between the compactness of the compressed files
and the fact that they aren’t downloaded very often, users shouldn’t notice the
downloads and in fact probably won’t be aware that the files were downloaded.
The ASP.NET AJAX January Futures CTP extends the Microsoft AJAX Library with the
JavaScript files listed in Figure 3-2. These files aren’t required if you only use the core
features of ASP.NET AJAX, but they add to the platform a variety of useful features
including support for animations and drag-and-drop operations.
Figure 3-2: January Futures CTP JavaScript files
File Description
PreviewScript.js Extensive library of classes (including control classes)
PreviewGlitz.js Animation classes and other classes for building
“glitzy” UIs
PreviewDragDrop.js _DragDropManager and other classes that support drag-
and-drop operations
PreviewWebParts.js AJAX support for ASP.NET Web parts
The sections that follow document the content and structure of the Microsoft AJAX
Library (including some of the features added by the January Futures CTP) and provide
helpful guidance to developers who are interested in understanding and extending it.
This example uses the String.format function, which is similar to the .NET
Framework’s String.Format method, to build a string without using concatenation
operators.
The Microsoft AJAX Library defines several global variables that provide easy access
from anywhere to parts of its own infrastructure. Among them are Sys.Application,
which represents the application and refers to an instance of Sys._Application;
Sys.Services.AuthenticationService, which provides access to the ASP.NET 2.0
membership service on the server (see Section 2.7.1); and Sys.Services.ProfileService,
which provides access to the ASP.NET 2.0 profile service on the server (see Section
2.7.2).
The Microsoft AJAX Library also creates an instance of its own Sys._Debug class and
assigns a reference to it to the global variable Sys.Debug. Sys._Debug contains useful
methods to assist in debugging, including assert, fail, trace, and traceDump,
facilitating JavaScript code like the following:
// Assert
var happy = false;
Sys.Debug.assert(happy == true, 'happy is NOT true', false);
The Microsoft AJAX Library changes that by adding OOP to JavaScript. At least it
creates the illusion of OOP; in truth, all it’s doing is making creative use of JavaScript
to make it seem as if you can define classes, namespaces, interfaces, and so on. But
the illusion is an effective one, and it is the foundation for the types featured in the
Script Core Library and the Base Class Library discussed in the next two sections.
To make JavaScript seem more like an object-oriented programming language, the
Microsoft AJAX Library exploits the fact that JavaScript allows functions to be treated
as data types and instantiated with the new operator. It also uses the prototype
property introduced in JavaScript 1.1 to make functions feel more like classes and to
enact the JavaScript equivalent of inheritance.
As an example, the code in Figure 3-5 implements a JavaScript “class” named Point.
The Point function acts as a constructor, and the statements inside the function
declare and initialize what are essentially instance fields named _x and _y.
Point.prototype is then used to define get_x and get_y methods that are included in
all instances of Point. This class implementation makes the following JavaScript code
perfectly legal:
Purists might argue that this isn’t really OOP, but it certainly feels like OOP. And it’s
very similar to the pattern that the Microsoft AJAX Library uses to implement classes.
Point.prototype =
{
get_x: function() { return this._x; },
get_y: function() { return this._y; }
}
Of course, most OOP programming languages support more than just classes; they also
support namespaces, interfaces, base classes and derived classes, and the like. Some
even support type reflection so that information about types can be discovered at run-
time.
Enter the second ingredient in the Microsoft AJAX Library’s recipe for adding OOP to
JavaScript: the Type class. Among other things, the Type class implements methods
for registering classes and namespaces so they can be reflected on at run-time. Its
registerClass method makes a class eligible for run-time discovery and allows the
registrar to specify a base class. Furthermore, Type defines an initializeBase method
that a “derived” class can call in its constructor to initialize the base class, as well as
a callBaseMethod for invoking methods in the base class. You can read all about Type
at http://ajax.asp.net/docs/ClientReference/Global/TypeClass/default.aspx and view
its source code in MicrosoftAjax.js. It is arguably the most important class in the entire
client framework.
An example will help paint a picture of how Type is combined with functions and
prototypes to add OOP-like behavior to JavaScript. The JavaScript in Figure 3-6 uses
Type.registerNamespace to register a namespace named Custom. Then it adds a class
named Person to the namespace. At the end, a call to the registerClass method added
to the Person class through Type.prototype registers the Person class with the
Microsoft AJAX Library.
Custom.Person = function(name)
{
this._name = name;
}
Custom.Person.prototype =
{
get_name: function() { return this._name; }
}
Custom.Person.registerClass('Custom.Person');
Once the Person class is defined in this manner, it can be exercised with the following
JavaScript code:
// Displays "Jeff"
window.alert(p.get_name());
// Displays "Custom.Person"
window.alert(Object.getTypeName(p));
Note the use of Object.getTypeName, which is one of the JavaScript base type
extensions mentioned in Section 3.1.
What if you wanted to derive from Person to create a Programmer class? Type helps
make that possible, too. Figure 3-7 shows how such a class might be implemented.
Note the call to initializeBase in the constructor, and the base class (Custom.Person)
specified in the registerClass method’s second parameter. Also note the call to
callBaseMethod in get_name to invoke the same method in the base class.
Custom.Programmer.prototype =
{
get_name: function()
{
var name = Custom.Programmer.callBaseMethod (this,
'get_name');
return name + ' (Programmer)';
},
get_language: function()
{
return this._language;
}
}
Custom.Programmer.registerClass ('Custom.Programmer',
Custom.Person);
The following JavaScript code creates a Programmer object and puts it through its
paces:
// Displays "C#"
window.alert(p.get_language());
// Displays "Wintellect.Programmer"
window.alert(Object.getTypeName(p));
The Script Core Library implements approximately 25 classes grouped into the five
namespaces listed in Figure 3-8. Some, like StringBuilder, are utility classes. Others,
such as JavaScriptSerializer and WebRequest, are fundamental to the operation of the
ASP.NET AJAX framework. The following code uses Sys.Net.WebRequest to launch an
asynchronous XML-HTTP request and resembles plumbing deep inside the Microsoft
AJAX Library that does the same:
Figure 3-9 lists some of the key classes and namespaces in the BCL. One of the most
important is the PageRequestManager class, which is the client half of the
UpdatePanel control and is discussed in greater detail in the next section. The classes
in the Sys.Preview.UI namespace (and its children) abstract HTML DOM elements and
open the door to animations, transparencies, drag-and-drop, client-side rendering of
server data, and other visual effects. A handful of these capabilities are accessible
through server controls (for example, the DragOverlayExtender control emits code
that wraps instances of Sys.Preview.UI.FloatingBehavior around DOM elements), but in
general, you have to write JavaScript that runs on the client to tap into the full power
of Sys.Preview.UI. Some of its features can, however, be leveraged using server
controls in the ASP.NET AJAX Control Toolkit.
To have some fun with the BCL (and see what it’s like to program it directly), try
inserting the following <script> block into an ASP.NET AJAX page that contains an
image whose ID is “SplashImage”:
<script type="text/javascript">
function pageLoad()
{
var image = new Sys.Preview.UI.Image ($get('SplashImage'));
var fade = new Sys.Preview.UI.Effects.FadeAnimation();
fade.set_target(image);
fade.set_effect (Sys.Preview.UI.Effects.FadeEffect.FadeIn);
fade.set_duration(3);
fade.set_fps(20);
fade.play();
}
</script>
For this code sample to work, you’ll need to download PreviewGlitz.js to the page.
Here’s how to download it with a ScriptManager (or ScriptManagerProxy) control:
Now display the page in your browser and watch the image.
Sections 3.6 and 3.7 provide additional information about selected BCL classes. The
ASP.NET AJAX Web site contains a detailed reference to them all at
http://ajax.asp.net/docs/ClientReference/default.aspx.
3.6 PageRequestManager
One BCL class that deserves special mention is Sys.WebForms.PageRequestManager,
which is implemented in MicrosoftAjaxWebForms.js and provides client support for
partial-page rendering. The UpdatePanel control facilitates partial-page rendering on
the server, but the PageRequestManager class, which is the client-side counterpart to
UpdatePanel, facilitates it on the client.
Figure 3-10 shows one way to implement such a feature. When the page loads,
JavaScript code registers an event handler for PageRequestManager’s pageLoaded
event. The args parameter passed to the event handler is a PageLoadedEventArgs
object, which has a get_panelsUpdated method that identifies the UpdatePanel
controls that were just updated. The event handler enumerates updated UpdatePanel
controls and calls a local helper function named flashPanels to flash each UpdatePanel
on and off three times.
if (panels.length > 0)
{
_panels = new Array(panels.length);
flashPanels(3);
}
}
function flashPanels(count)
{
_count = (count << 1) + 1;
window.setTimeout(toggleVisibility, 50);
}
function toggleVisibility()
{
for (i=0; i < _panels.length; i++)
_panels[i].set_visible(!_panels[i].get_visible());
if (--_count > 0)
window.setTimeout(toggleVisibility, 50);
}
</script>
Figure 3-11 lists some of the control classes featured in PreviewScript.js. Not shown
are validator controls such as RequiredFieldValidator and RegexValidator, which serve
the same purpose in Microsoft AJAX Library applications that ASP.NET validator
controls do in ASP.NET applications. Remember also that the Microsoft AJAX Library
includes a Sys.Preview.UI.Data namespace featuring a very rich set of data controls
with names such as ListView and ItemView. Though beyond the scope this document,
the data controls enable client-side data binding to data sources on the server in the
same way that GridView, DetailsView, and other ASP.NET server controls facilitate
rich server-side data binding.
All the classes in Figure 3-11 derive either directly or indirectly the Sys.UI.Control
class found in the Script Core Library. As such, they inherit a common set of features.
Among those features are get_visible and set_visible methods for controlling visibility
in a browser-independent way, a get_element method for accessing underlying DOM
elements, and the ability to bubble DOM events.
Figure 3-12 contains selected portions of a DHTML page that implements an interactive
UI driven entirely from the client. The UI consists of a text box, a button, and an
empty <span> element. When the button is clicked, the onClick function uses the
browser DOM to read the contents of the text box and display it to the right of the
button by assigning it to the <span> element’s innerHTML property. As a result, what
the user types into the text box is echoed to the page when the button is clicked.
<script type="text/javascript">
function onClick()
{
document.getElementById('Output').innerHTML =
document.getElementById('Input').value;
}
</script>
Figure 3-13 contains the equivalent page written with Microsoft AJAX Library HTML
controls. The JavaScript code contains a pageLoad function that wraps TextBox,
Button, and Label controls around the corresponding DOM elements. It also registers a
handler for the Button control’s click events. (If present in an ASP.NET AJAX Web
page, a pageLoad function is automatically called after the page loads and the library
is initialized.) The handler echoes the user’s input to the page by reading it from the
TextBox control and writing it to the Label control. Note that the JavaScript code
never accesses the browser DOM directly; instead, it accesses it indirectly by
interacting with the controls that wrap the DOM elements.
<script type="text/javascript">
var g_textBox;
var g_label;
function pageLoad()
{
g_textBox = new Sys.Preview.UI.TextBox($get('Input'));
var button = new Sys.Preview.UI.Button($get('MyButton'));
g_label = new Sys.Preview.UI.Label($get('Output'));
button.initialize();
button.add_click(onClick);
}
function onClick()
{
g_label.set_text(g_textBox.get_text());
}
</script>
Are there advantages to writing JavaScript his way? Yes—in fact, there are two. One,
the same code works not just in Internet Explorer, but in Firefox and Safari and all the
other browsers that ASP.NET AJAX supports. Rather than devote time to testing and
tweaking the code to work in different browsers, you can let Microsoft sweat those
details for you. Two, the control classes simplify certain tasks involving HTML controls.
Rather than iterate through the items in a <select> element to find the one you wish
to select, for example, you can call Selector.set_selectedValue to select the item.
3.8 xml-script
The Microsoft AJAX Library can be programmed imperatively using JavaScript. It can
also be programmed declaratively using a language known as xml-script.
Support for xml-script is found in PreviewScript.js, which is part of the ASP.NET AJAX
Futures CTP. xml-script played a huge role in pre-Beta releases of ASP.NET AJAX, then
known by the code name “Atlas.” (In early releases, ASP.NET AJAX server controls
rendered xml-script instead of JavaScript.) Its role is greatly diminished today, and in
fact it doesn’t have to be used at all. But certain tasks in the Microsoft AJAX Library—
especially ones that involve templated controls such as Sys.Preview.UI.Data.ListView—
are implemented more easily in xml-script than in JavaScript. Therefore, xml-script is
a feature that ASP.NET AJAX developers should at least be aware of, whether they
choose to use it or not.
Figure 3-14 shows the xml-script version of the page in Figure 3-13. The pages are
identical on the outside, but very different on the inside. Elements such as <textBox>
and <button> in xml-script declare instances of TextBox and Button controls and link
them to DOM elements. The <click> element inside the <button> element registers a
handler for click events, and the <invokeMethodAction> element inside the <click>
element invokes a method named evaluateIn on an object named “TextBinding” when
a click event is raised. What is “TextBinding?” It’s a Binding object (an instance of
System.Preview.Binding) created with a <binding> element. It binds the text property
of the TextBox control to the text property of the Label control. When the binding is
evaluated (that is, when its evaluateIn method is called), the contents of the TextBox
control are copied to the Label control.
<script type="text/xml-script">
<page
xmlns:script="http://schemas.microsoft.com/xml-script/2005">
<components>
<textBox id="Input" />
<button id="MyButton">
<click>
<invokeMethodAction target="TextBinding"
method="evaluateIn" />
</click>
</button>
<label id="Output">
<bindings>
<binding id="TextBinding" dataContext="Input"
dataPath="text" property="text" automatic="false" />
</bindings>
</label>
</components>
</page>
</script>
This is a very different way of exercising the Microsoft AJAX Library, and the jury is
still out on what role, if any, xml-script will play in future versions of ASP.NET AJAX.
On the negative side, there are currently no tools to support it (no special editors or
IntelliSense engines, for example). It imposes extra overhead on the client due to XML
parsing, it’s difficult to debug, and there’s precious little documentation describing it.
On the positive side, with the proper tool support, writing xml-script could be easier
than writing JavaScript, and an XML scripting language brings to mind some enticing
possibilities involving XAML.
4.0 Summary
AJAX has gained widespread popularity in recent years as a means for making Web
applications richer and more interactive—in short, to make them feel less like Web
applications and more like rich clients. ASP.NET AJAX is an AJAX framework that
abstracts and simplifies AJAX. With it, developers who know little about JavaScript,
XML-HTTP, and other pillars of AJAX can write AJAX-enabled applications and get
them to market in a timely fashion.
ASP.NET AJAX shortens the development cycle by providing high-level AJAX wrappers
such as UpdatePanel controls on the server and a rich library of JavaScript types and
extensions on the client. The server half of the platform, the ASP.NET 2.0 AJAX
Extensions, transforms ASP.NET 2.0 into a great platform for AJAX applications. The
client half, the Microsoft AJAX Library, makes browsers a richer and more productive
environment in which to work and offers not only browser independence, but
independence from the server platform as well.