The ASP.NET AJAX Extensions

W
Document Sample
scope of work template
							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