Inside ASP.NET Partial Rendering

The ScriptManager Control Does the Trick

CoreCoder

LANGUAGES: C#

ASP.NET VERSIONS: 2.0 | 3.5

 

Inside ASP.NET Partial Rendering

The ScriptManager Control Does the Trick

 

By Dino Esposito

 

The chief factor that enables AJAX functionality in a Web page is the ability to issue out-of-band HTTP requests. An out-of-band call indicates an HTTP request that is placed by bypassing the internal browser s engine and without triggering the usual set of related operations, such as page reload, history list, and offline storage update. In an AJAX scenario, an HTML page executes the call via script using a proxy component based on the XMLHttpRequest object. The XMLHttpRequest object relies on the browser-internal API to make the connection, but it goes straight to the point: connect to the URL without performing any other auxiliary operation.

 

You can use XMLHttpRequest to add simple and relatively limited AJAX capabilities to pages. However, the more sophisticated these capabilities become, the more you need to evolve the classic model of a Web page. Each XMLHttpRequest operation requires a bit of script code to handle the call and refresh the user interface. Multiple operations, then, are to be grouped together in a component to express a higher level behavior, such as paging through a collection of displayed data. As a result, the need emerges for a new generation of Web components (i.e., server controls).

 

It s amazing to see how the introduction of XMLHttpRequest raised the need of a new Web architecture in a relatively short time. Building a true AJAX application is not a trivial task; in most cases, a simpler facelift to the existing application is enough to revitalize it and make users happier. Enter partial rendering.

 

ASP.NET Partial Rendering

Conceptually, partial rendering consists in HTTP requests that bring back to the client only the delta between the old and new page. Expressed as plain HTML markup, the delta is then merged to the existing page DOM without forcing a full page reload. This basic idea can be implemented in at least a couple of ways. A possible approach entails that you define a manager control and have individual controls register with the manager if interested in being conditionally updated across postbacks. Another possibility is that you group together updatable controls in a container and register the container with the manager. ASP.NET AJAX takes the latter route with its partial rendering API.

 

From the developer s perspective, partial rendering consists of wrapping updatable regions of the page with a new server control: the UpdatePanel control. Using the programming interface of the UpdatePanel, you define under which conditions the child controls of the panel refresh over a postback. By default, the content of a panel refreshes when any of its constituent controls post back and when any other updatable panel in the same page refreshes. The UpdatePanel control, though, is only the instrument you use to define updatable areas of the page. The real delta of the new page is expressed as the union of the markup generated by one or more UpdatePanel instances in the same ASPX page. Another control operates in the dark to make partial rendering happen. This control is the ScriptManager control.

 

It s Only a Trick, Baby

Partial rendering is a software trick that makes possible getting AJAX functionalities on top of the traditional Web architecture based on a synchronous request/response challenge. The ASP.NET page works as usual, and its child controls are allowed to post back as usual. During the loading phase, though, the ScriptManager control silently injects a piece of script code in the client page. This script registers a handler for the form s submit event. The handler intercepts any postback operations and does two things. First, it tells the browser that the operation has been cancelled. Second, it sends the same request to the destination using XMLHttpRequest. The request is sent asynchronously and a built-in callback is set to receive and parse the response. Finally, the same callback is responsible for updating the user interface accordingly. In the end, the programmer adds a few UpdatePanels in the source page and one instance of the ScriptManager. Everything else is done as usual; the page lifecycle is totally preserved.

 

For the partial rendering to work, though, the role of the ScriptManager control is key. In the rest of this article, I ll address recognizing its merits and illustrate its real behavior.

 

Analysis of the Client HTML

As mentioned, any ASP.NET AJAX page must have exactly one instance of the ScriptManager control decorated with the runat attribute and placed within the boundaries of a server-side form. The ScriptManager control adds a

 

The Sys.WebForms.PageRequestManager class is a JavaScript class defined in the MicrosoftAjaxWebForms.js file. The _initialize method on this class is ultimately responsible for setting up the hook for the form s submit event. It s not coincidental, therefore, that the second argument to the function is the DOM reference to the page s form object. The first argument, instead, is the ID of the script manager control in the page. Why is this piece of information required? To find out, let s analyze the content of a typical partial rendering request.

 

Analysis of the Request

When partial rendering is enabled, the original browser request is lost and the client-side partner of the ScriptManager control namely, the Sys.WebForms.PageRequestManager class takes care of preparing a new one with some slight changes. In particular, a partial rendering request must contain some information that makes it easy to distinguish it from regular ASP.NET requests. As illustrated in Figure 1, a partial rendering request has an extra HTTP request header (x-microsoftajax) set to a particular value (delta=true). In addition, the body of the HTTP request is slightly different from the body of the browser request that has just been swallowed by the AJAX infrastructure. As shown in Figure 2, the request body contains an extra form argument ScriptManager1. Where does this name come from? It s simply the ID of the server-side ScriptManager control. It was made available to the client-side PageRequestManager class via the above script that calls the _initialize method.

 


Figure 1: Request headers of a partial rendering operation.

 


Figure 2: Request body and response of a partial rendering operation.

 

The text assigned to the ScriptManager1 token in the request is a pipe-separated string made of two pieces of information: the ID of the UpdatePanel control to update during the request and the ID of the control responsible for the postback. This chunk of information is carried to the server for the ScriptManager control to process. When and how does the ScriptManager get this data? It s the job of the ASP.NET page lifecycle to ensure that the ScriptManager control gets it.

 

Internals of the ScriptManager Control

The body of the request is processed on the server and fills up the server-side Request.Form collection. For each parameter name that shows up in Figure 2, such as ScriptManager1, Button1, and __EVENTTARGET, the ASP.NET page will find a match with the ID of a control in the page tree. If a match is found that is, a server control named ScriptManager1 is found the page checks whether the control implements the IPostBackDataHandler interface:

 

public interface IPostBackDataHandler

{

 bool LoadPostData(string postDataKey,

    NameValueCollection postCollection);

 void RaisePostDataChangedEvent();

}

 

The LoadPostData method is responsible for updating the state of the control using any information posted through the Request.Form collection. In particular, the ScriptManager class uses any carried information to set the value of its AsyncPostBackSourceElementID property and track which UpdatePanel it has to update at rendering time.

 

The Rendering Phase

In the ASP.NET lifecycle the rendering phase begins with the PreRender event. The ScriptManager control hooks up the event and runs the following code:

 

if (this.IsInAsyncPostBack)

{

   this.Page.SetRenderMethodDelegate(

         new RenderMethod(this.RenderPageCallback));

}

 

On pages and controls, the SetRenderMethodDelegate method is a way to override the rendering algorithm. In the end, when a partial rendering request is made, the page lifecycle runs as usual except the rendering phase when the response for the client is generated.

 

In the PreRenderComplete event handler, the ScriptManager emits