430 likes | 772 Views
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 & Server Controls. Application
E N D
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 & Server Controls Application Services
Server Controls Script Management Partial-Page Rendering Futures CTP ScriptManager UpdatePanel DragOverlay- Extender ScriptManager- Proxy Update- 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>
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>
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) { ... } }
<script src="ZipCodeService.asmx/js" type="text/javascript"> </script> Declaring a Service Reference <asp:ScriptManager ID="ScriptManager1" Runat="server"> <Services> <asp:ServiceReference Path="ZipCodeService.asmx" /> </Services> </asp:ScriptManager>
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()); }
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 Server: ASP.NET Development Server/8.0.0.0 Date: Fri, 29 Dec 2006 21:06:17 GMT X-AspNet-Version: 2.0.50727 Cache-Control: private, max-age=0 Content-Type: application/json; charset=utf-8 Content-Length: 16 Connection: Close ["REDMOND","WA"] JSON-encoded input JSON-encoded output
ScriptHandlerFactory • Wraps (replaces) default ASP.NET ASMX handler • 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 <httpHandlers> <remove verb="*" path="*.asmx" /> <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, ..." /> </httpHandlers>
ASMX Request Handling ASMX Extensions ScriptHandler- Factory RestClient- ProxyHandler Helper Classes *.asmx *.asmx/js RestHandler *.asmx/methodname "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 {"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> JSON vs. XML Point p = new Point(100, 200);
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
var PageMethods = function() { PageMethods.initializeBase(this); this._timeout = 0; this._userContext = null; this._succeeded = null; this._failed = null; } PageMethods.prototype = { ... } Enabling Page Methods <asp:ScriptManager ID="ScriptManager1" EnablePageMethods="true" Runat="server" />
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); }
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()); }