The ASP.NET AJAX Extensions
Document Sample


The ASP.NET AJAX Extensions
Jeff Prosise
Cofounder, Wintellect
jeffpro@wintellect.com
Architecture
ASPX ASMX
ASP.NET AJAX Extensions
Application Services
Bridge
Server
Controls
Asynchronous
Communications
ASP.NET 2.0
Page Framework Application
& Server Controls Services
Server Controls
Script Partial-Page
Management Rendering Futures CTP
DragOverlay-
ScriptManager UpdatePanel
Extender
ScriptManager- Update-
Proxy Progress ProfileService
Timer
ScriptManager
• Starting point for ASP.NET AJAX pages
• What does ScriptManager do?
– Downloads JavaScript files to client
– Enables partial-page rendering using UpdatePanel
– Provides access to Web services via client-side proxies
– Manages callback timeouts and provides error handling
options and infrastructure
– Provides registration methods for scripts
– Enables ASP.NET AJAX localization support
• Every page requires one ScriptManager instance!
ScriptManager Schema
<asp:ScriptManager ID="ScriptManager1" Runat="server"
EnablePartialRendering="true|false"
EnablePageMethods="true|false"
AsyncPostBackTimeout="seconds"
AsyncPostBackErrorMessage="message"
AllowCustomErrorsRedirect="true|false"
OnAsyncPostBackError="handler"
EnableScriptGlobalization="true|false"
EnableScriptLocalization="true|false"
ScriptMode="Auto|Inherit|Debug|Release"
ScriptPath="path">
<Scripts>
<!-- Declare script references here -->
</Scripts>
<Services>
<!-- Declare Web service references here -->
</Services>
</asp:ScriptManager>
Script References
"Name" references load script resources
<asp:ScriptManager ID="ScriptManager1" Runat="server">
<Scripts>
<asp:ScriptReference Name="PreviewScript.js"
Assembly="Microsoft.Web.Preview" />
<asp:ScriptReference Name="PreviewDragDrop.js"
Assembly="Microsoft.Web.Preview" />
<asp:ScriptReference Path="~/Scripts/UIMap.js" />
</Scripts>
</asp:ScriptManager>
"Path" references load script files
Service References
<asp:ScriptManager ID="ScriptManager1" Runat="server">
<Services>
<asp:ServiceReference Path="ZipCodeService.asmx" />
</Services>
</asp:ScriptManager>
ScriptManagerProxy
• "Proxy" for ScriptManager controls declared in
master pages
• Lets content pages declare script and service
references
<asp:ScriptManagerProxy ID="ScriptManagerProxy1" Runat="server">
<Scripts>
<!-- Declare additional script references here -->
</Scripts>
<Services>
<!-- Declare additional service references here -->
</Services>
</asp:ScriptManagerProxy>
UpdatePanel
• Partial-page rendering in a box
– Clean round trips to server and flicker-free updates
– Requires no knowledge of JavaScript or AJAX
• Leverages client-side PageRequestManager class
– EnablePartialRendering="true" in ScriptManager
• Supports explicitly defined triggers
– By default, postbacks from all controls in an
UpdatePanel are converted into async callbacks
– Triggers expand (or shrink) postback->callback scope
• Works in virtually all scenarios
UpdatePanel Schema
<asp:ScriptManager ID="ScriptManager1" Runat="server"
EnablePartialRendering="true" />
.
.
.
<asp:UpdatePanel ID="UpdatePanel1" Runat="server"
UpdateMode="Always|Conditional"
ChildrenAsTriggers="true|false">
<Triggers>
<!-- Define triggers (if any) here -->
</Triggers>
<ContentTemplate>
<!-- Define content here -->
</ContentTemplate>
</asp:UpdatePanel>
Triggers
• AsyncPostBackTrigger
– Converts postbacks into asynchronous callbacks
– Typically used to trigger updates when controls outside
an UpdatePanel post back and fire events
– If ChildrenAsTriggers="false", can be used to specify
which controls inside UpdatePanel should call back
rather than post back
• PostBackTrigger
– Allows controls inside an UpdatePanel to post back
– Typically used to allow certain controls to post back
when ChildrenAsTriggers="true"
Triggers Example
<asp:UpdatePanel ID="UpdatePanel1" Runat="server"
UpdateMode="Conditional">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Button1" />
<asp:AsyncPostBackTrigger ControlID="TreeView1"
EventName="TreeNodeExpanded" />
<asp:AsyncPostBackTrigger ControlID="TreeView1"
EventName="TreeNodeCollapsed" />
<asp:PostBackTrigger ControlID="Button2" />
</Triggers>
<ContentTemplate>
...
</ContentTemplate>
</asp:UpdatePanel>
Periodic Updates
• Combine UpdatePanel with Timer control to
implement pages that perform periodic updates
• Use Timer control Tick events as triggers
<asp:Timer ID="Timer1" Runat="server" Interval="5000"
OnTick="OnTimerTick" />
...
<asp:UpdatePanel UpdateMode="Conditional" ...>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Timer1" />
</Triggers>
...
</asp:UpdatePanel>
UpdatePanel
UpdateProgress
• Companion to UpdatePanel controls
• Displays custom template-driven UI for:
– Indicating that an async update is in progress
– Canceling an async update that is in progress
• Automatically displayed when update begins or
"DisplayAfter" interval elapses
UpdateProgress Schema
<asp:UpdateProgress ID="UpdateProgress1" Runat="server"
DisplayAfter="milliseconds"
DynamicLayout="true|false"
AssociatedUpdatePanelID="UpdatePanelID">
<ProgressTemplate>
<!-- Declare UpdateProgress UI here -->
</ProgressTemplate>
</asp:UpdateProgress>
UpdateProgress Example
Display after ½ second
<asp:UpdateProgress DisplayAfter="500" ...>
<ProgressTemplate>
<asp:Image ID="ProgressImage" Runat="server"
ImageUrl="~/Images/SpinningClock.gif" />
</ProgressTemplate>
</asp:UpdateProgress>
Animated GIF
Canceling an Update
<asp:UpdateProgress DisplayAfter="500" ...>
<ProgressTemplate>
<b>Working...</b>
<asp:Button ID="CancelButton" Runat="server" Text="Cancel"
OnClientClick="cancelUpdate(); return false" />
</ProgressTemplate>
</asp:UpdateProgress>
<script type="text/javascript">
function cancelUpdate()
{
var obj = Sys.WebForms.PageRequestManager.getInstance();
if (obj.get_isInAsyncPostBack())
obj.abortPostBack();
}
</script>
UpdateProgress
ASP.NET AJAX Web Services
• ASP.NET AJAX supports ASMX Web methods as
endpoints for asynchronous AJAX callbacks
– Efficient on the wire (no SOAP or XML)
– Efficient on the server (no page lifecycle)
• ScriptService attribute on server indicates Web
service is callable from client-side script
• JavaScript proxy on client enables JavaScript
clients to call Web methods on server
– Proxies generated by service references
• WCF support coming in future release
Script-Callable Web Service
[System.Web.Script.Services.ScriptService]
public class ZipCodeService : System.Web.Services.WebService
{
[System.Web.Services.WebMethod]
public string[] GetCityAndState (string zip)
{
...
}
}
Declaring a Service Reference
<asp:ScriptManager ID="ScriptManager1" Runat="server">
<Services>
<asp:ServiceReference Path="ZipCodeService.asmx" />
</Services>
</asp:ScriptManager>
<script src="ZipCodeService.asmx/js" type="text/javascript">
</script>
Consuming a Web Service
ZipCodeService.GetCityAndState("98052", onCompleted);
.
.
.
function onCompleted (result)
{
window.alert(result);
}
Handling Errors
ZipCodeService.GetCityAndState("98052", onCompleted, onFailed);
.
.
.
function onCompleted (result, context, methodName)
{
window.alert(result);
}
function onFailed (err, context, methodName)
{
window.alert(err.get_message());
}
Web Services
ASMX Wire Format
Request
POST /AtlasRC/ZipCodeService.asmx/GetCityAndState HTTP/1.1
Accept: */*
Accept-Language: en-us
Referer: http://localhost:1997/AtlasRC/ZipCodePage.aspx
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; ...)
Host: localhost:1997
Content-Length: 15
Connection: Keep-Alive
Cache-Control: no-cache
{"zip":"98052"}
Response
HTTP/1.1 200 OK
JSON-encoded Server: ASP.NET Development Server/8.0.0.0
Date: Fri, 29 Dec 2006 21:06:17 GMT
input X-AspNet-Version: 2.0.50727
Cache-Control: private, max-age=0
Content-Type: application/json; charset=utf-8
JSON-encoded Content-Length: 16
Connection: Close
output
["REDMOND","WA"]
ScriptHandlerFactory
• Wraps (replaces) default ASP.NET ASMX handler
<httpHandlers>
<remove verb="*" path="*.asmx" />
<add verb="*" path="*.asmx" validate="false"
type="System.Web.Script.Services.ScriptHandlerFactory,
System.Web.Extensions, ..." />
</httpHandlers>
• Extends ASMX model to support "special" URLs
– JavaScript proxy generation (*.asmx/js)
– Calls to Web methods (*.asmx/methodname)
• Gateway to ASP.NET AJAX ASMX extensions
ASMX Request Handling
ASMX Extensions
RestClient-
*.asmx *.asmx/js
ProxyHandler
ScriptHandler- Helper
Factory Classes
*.asmx/methodname RestHandler
"Normal" ASMX calls
WebService-
HandlerFactory Default ASMX handler
JSON
• JavaScript Object Notation
– Lightweight data interchange format
– Easier to read and write (and less verbose) than XML
– Based on subset of JavaScript programming language
• Default interchange format in ASP.NET AJAX
– Supported on server by Microsoft.Web.Script.-
Serialization.JavaScriptSerializer class
– Supported on client by Sys.Serialization.-
JavaScriptSerializer class
• JSON home page: www.json.org
JSON vs. XML
Point p = new Point(100, 200);
JSON
{"IsEmpty":false,"X":100,"Y":200}
XML
<?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>
The ScriptMethod Attribute
• Optional attribute for script-callable Web methods
• Offers added control over wire format of calls
Property Description
UseHttpGet True = Use HTTP GET, False = Use HTTP POST (default)
ResponseFormat ResponseFormat.Xml or ResponseFormat.Json (default)
XmlSerializeString True = Serialize everything (including strings) as XML,
False = Serialize response strings as JSON (default)
(Only valid if ResponseFormat == ResponseFormat.Xml)
Using ScriptMethod
[System.Web.Script.Services.ScriptService]
public class ZipCodeService : System.Web.Services.WebService
{
[System.Web.Services.WebMethod]
[System.Web.Script.Services.ScriptMethod
(ResponseFormat=ResponseFormat.Xml)]
public XmlDocument GetCityAndState (string zip)
{
...
}
}
Method returns XML document, so serialize as
XML rather than JSON
Page Methods
• Script-callable Web methods built into pages
– Implemented in ASPXes, not ASMXes
– Same efficiencies as ASMX Web methods
• Simpler than writing a full-blown Web service
– Do not require service references
– Do not require dedicated ASMX files
• Must be public static methods
• Must be enabled via ScriptManager.-
EnablePageMethods (disabled by default)
• Called through PageMethods proxy on client
Enabling Page Methods
<asp:ScriptManager ID="ScriptManager1" EnablePageMethods="true"
Runat="server" />
var PageMethods = function() {
PageMethods.initializeBase(this);
this._timeout = 0;
this._userContext = null;
this._succeeded = null;
this._failed = null;
}
PageMethods.prototype = {
...
}
Defining a Page Method
public partial class MyPage : System.Web.UI.Page
{
[System.Web.Services.WebMethod]
public static string[] GetCityAndState (string zip)
{
...
}
...
}
Calling a Page Method
PageMethods.GetCityAndState("98052", onComplete);
.
.
.
function onComplete(result)
{
window.alert(result);
}
Page Methods
Built-In Web Services
• AuthenticationService
– Front end to ASP.NET 2.0 membership service
– Call through Sys.Services.AuthenticationService proxy
• Global instance of Sys.Services._AuthenticationService
• ProfileService
– Front-end to ASP.NET 2.0 profile service
– Call through Sys.Services.Profile proxy
• Global instance of Sys.Services._ProfileService
• Accessed through ScriptHandlerFactory on server
– *_AppService.axd -> ScriptHandlerFactory
Using AuthenticationService
Sys.Services.AuthenticationService.login (username, password,
false, null, null, onLoginCompleted, onLoginFailed);
...
function onLoginCompleted(result, context, methodName)
{
window.alert(result ? 'Login succeeded' : 'Login failed');
}
function onLoginFailed(err, context, methodName)
{
window.alert(err.get_message());
}
Loading Profile Properties
Pass null to load all profile properties
Sys.Services.ProfileService.load(['ScreenName'], onLoadCompleted,
onLoadFailed);
...
function onLoadCompleted(result, context, methodName)
{
window.alert(Sys.Services.ProfileService.properties.ScreenName);
}
function onLoadFailed(err, context, methodName)
{
window.alert(err.get_message());
}
Saving Profile Properties
Pass null to save all profile properties
Sys.Services.ProfileService.properties.ScreenName = 'Bob';
Sys.Services.ProfileService.save(['ScreenName'], onSaveCompleted,
onSaveFailed);
...
function onSaveCompleted(result, context, methodName)
{
window.alert('Save succeeded');
}
function onSaveFailed(err, context, methodName)
{
window.alert(err.get_message());
}
Discussion
Related docs
Get documents about "