Gain Control of Partial Rendering with Data Items
Pack Custom Data in UpdatePanel’s Payloads
October 30, 2009
CoreCoder
LANGUAGES: C#
ASP.NETVERSIONS: 2.0
Gain Control of Partial Rendering with Data Items
Pack Custom Data in UpdatePanel s Payloads
By Dino Esposito
Partial rendering is what makes ASP.NET AJAX unique in thearena of frameworks for AJAXdevelopment. AJAX represents a paradigm shift for Web developers; partialrendering does the trick of letting developers use the same model they re usedto that is, classic ASP.NET but in the context of AJAX applications. Withpartial rendering, your page keeps on working through postbacks and viewstate,but bypasses the browser whenever a form submission occurs. Instead of goingthrough a regular SUBMIT, your page will use XMLHttpRequest, thus circumventinga full refresh.
The UpdatePanel control is the nerve center of partialrendering. Each chunk of markup wrapped up in the body of an UpdatePanelcontrol is refreshed independently from the remainder of the page. To transforma regular ASP.NET page in an ASP.NET AJAX page, you simply partition the bodyof the page in an array of updatable regions, including nested regions. Next,using triggers and other properties, you set the rules that govern the refreshof the regions.
However, not all pages lend themselves to be divided in aset of small updatable regions. Unfortunately, not in all cases can youreasonably think of having an individual region for each portion of markup thatmust be independently updated. In general, one could always design a new pageto fulfill this requirement, but here you are addressing existing pages, withtheir own fixed layout and their largely hard-coded logic. One of the keybenefits of partial rendering is the speed of AJAXification and the limitedimpact on existing pages. So what s the issue?
Suppose you have wrapped your entire page markup inupdatable regions. What if the update of a region may trigger the update onanother region, or even on one control in another region? What if you realizethat you need to update one control that is not contained in an updatableregion? And what if the logical update requires some work on the client?
Similar issues were raised early in the review process ofASP.NET AJAX, which lead to the introduction of a particular method in theScriptManager class, the RegisterDataItem method. While I can t say that thismethod is for common use, it certainly makes it possible for developers of AJAXpages and controls to add features that otherwise would be impractical with thestandard set of partial rendering functionalities.
The RegisterDataItem Method
Defined in the ScriptManager class, the RegisterDataItemmethod sets a server-generated string that will be added to the response of theongoing partial rendering update. This string is appended to the standardresponse and is extracted and processed by the client-side AJAXframework. Here are the signature and implementation of the method (by the way,you can access the full source code of the ASP.NET AJAX Extensions version 1.0from http://ajax.asp.net/downloads):
public void RegisterDataItem(Control control,
string dataItem, bool isJsonSerialized)
{
this.PageRequestManager.RegisterDataItem(control,
dataItem, isJsonSerialized);
}
The first argument indicates on behalf of which component(page or server control) the data is being registered. The second argumentindicates the string to append. Finally, the third argument is a Boolean valuethat indicates whether the string is JSON-encoded text or simply plain text.
It is interesting to notice that the ScriptManager smethod simply cascades to a similar, but static, method on thePageRequestManager internal class. This method simply checks whether there s anAJAX postback operation going on,then adds the specified string to an internal collection to be flushed to theresponse stream during the rendering stage.
The client framework of ASP.NET AJAX also features a pagerequest manager class, specifically named Sys.WebForms.PageRequestManager. Youshould be able to see the symmetry. The server-side PageRequestManager preparesthe data for sending and the client-side PageRequestManager gives client code achance to retrieve it and process via JavaScript. I ll return to this and otherprogramming aspects in a moment. For now, let me illustrate the motivation foradditional data items with a concrete example excerpted from the same ASP.NETAJAX Extensions source code.
Data Items and the Timer Control
The System.Web.UI.Timer control is one of the few newserver controls introduced by ASP.NET AJAX Extensions. It generates the scriptcode that sets up a client timer and binds it to some code that performs apostback whenever the timer expires:
Interval="10000" OnTick="Timer1_Tick" EnableViewState="False"/> On the server, a Tick event is fired whenever the timerexpires; based on the preceding code snippet, a postback occurs every 10seconds and will be processed through the Timer1_Tick method: protected void Timer1_Tick(object sender, EventArgs e) { // Code to run everyinterval} The Interval property sets the interval of the timer inmilliseconds; the Enabled property starts and stops the timer. The Timercontrol uses the data items feature internally to reflect any new valuesassigned on the server to the Interval and Enabled properties. As you can guess, the data items feature proves helpfulwhen a given functionality is implemented in both the server and the client,and changes that occurred on the server must be reflected on the client.Partial rendering does a good job reflecting on the client any changes that occurredto the markup on the server. But when you need to apply the same pattern to rawdata properties, you need data items in addition to partial rendering. The Timercontrol has no markup, but still needs to keep its client and server state insync. Let s dig out the source code of the control. In the pre-render eventhandler, the Timer control does the following: protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); if(this._stateDirty && this.ScriptManager.IsInAsyncPostBack) { this._stateDirty = false; this.ScriptManager.RegisterDataItem(this, this.GetJsonState(), true); } : } The control first checks whether it is engaged in an AJAXpostback and whether its internal state has been modified. If so, it resets theflag of the state change and registers a data item in the form of a JSONstring. As mentioned, this string the output of the internal GetJsonState function will be appended to the response and further processed on the client. That sall that a page or a control needs to do to forward extra and custominformation to the client during a partial rendering operation. You have no constraints as far as the format of the dataitem is concerned. It s entirely up to you and, as a page or control developer,you re responsible for both serialization and deserialization. However, theASP.NET AJAX framework provides some JSON facilities. Let s see what the Timercontrol does: private string GetJsonState(){ return ("[" +(this.Enabled ? "true" : "false") + "," + this.Interval.ToString() + "]"); } The control returns a string like the following: [true,1000] More importantly, it marks it as a JSON string. It is theJSON representation of a two-element array, and it will be deserialized to aJavaScript object on the client using the eval function. From a logicalstandpoint, the Timer control serves up an array with the current server-sidevalues of two of its properties, Enabled and Interval. These two propertiesform the server-side state of the control. To grasp the importance andusefulness of the data items feature, you need to understand why the Timercontrol needs to push this data to the client. As mentioned, the Timer control posts back automaticallywhenever the interval expires. The control is, in essence, an instance of the browser stimer object managed through the setTimeout method of the browser s windowobject. A client timer is not natively a tool to run a piece of code every n milliseconds until it is stopped. Moresimply, it is a tool that waits the specified number of milliseconds beforeexecuting once. After that, the timer is gone. It is in stand-by mode, but is nolonger triggering the associated code. To reiterate the associated code, youneed to repeatedly re-enable the timer. In doing so, you could vary theinterval. Because the Timer control is hard-coded to do a postback whenever itexpires, only the server code may change the value of the Interval and Enabledproperties. If any of these properties is changed during a regular postback,there s no problem: an updated script will be uploaded for the timer as part ofthe new page. But what about partial rendering postbacks? In this case, the data items feature allows the control topush to the client the delta of its state so that already downloaded clientscript can update the timer object. The Timer control, as well as most AJAXcontrols, downloads a script file with its client-side object model. Insidethis code you ll find the function to post process the data items (see the filemicrosoftajax.timer.js). A Quick Example I struggled enough with the task of finding a greatexample for using RegisterDataItem. All in all, I still believe that the bestexample is the Timer control. RegisterDataItem is helpful when the followingconditions are met: Need to push server-generated data to the client. Need to further process this data on the clientto sync up the user interface with the application s state. There are many scenarios where you need to push serverdata to the client; but not that many that require you to further process thedata on the client. In most cases, you can push ready-to-display data, thuszeroing the work required on the client. Look at Figure 1. RegisterDataItem isreally necessary when the amount of client script is nonzero; all things considered,it represents the most efficient way of accomplishing that task. This isdefinitely true for the timer example.
Figure 1: Schema for usingRegisterDataItem. Let s consider another example. Predictive fetch is one ofthe most important AJAX patterns becauseit provides guidance on how to make the browser more responsive by anticipatinguser actions and calls the server in advance. Imagine a page that provides alist of customers. When users select a customer, the page promptly shows allcustomer details. You can quickly code this through partial rendering using aDropDownList, a DetailsView, and a couple of ObjectDataSource controls. A userthat selects a customer will likely need to see orders, as well. If youretrieve orders along with customer details, you keep the page s user interfacefrozen, and the Web server busy, for too long. You could, for example, serve usersthe customer details and upload the customer ID as a separate piece ofinformation. A related script will take that information and place a separateand asynchronous call to get orders. Figure 2 shows an instance of thepredictive fetch pattern.
AutoPostBack="true" AppendDataBoundItems="true" DataSourceID="CustomersDataSource" DataTextField="CompanyName" DataValueField="ID" OnSelectedIndexChanged="CustomerSelected" OnPreRender="CustomerList_PreRender"> TypeName="ProAspNet20.DAL.Customers" SelectMethod="LoadAll"> UpdateMode="Conditional"> DataSourceID="CustomerViewDataSource"/> TypeName="ProAspNet20.DAL.Customers" SelectMethod="Load"> PropertyName="SelectedValue" /> [orders here] Figure 2: The markupof a predictive fetch page. Processing Data Items on the Client Registered data items are passed to the clientinfrastructure of ASP.NET AJAX through the dataItems property of the event datafor the pageLoading, pageLoaded, and endRequest events. The dataItems propertyis a key/value dictionary where the key is the ID of the control thatreferences the data or __Page if the referrer is the ASP.NET page. Here s howthe sample page specifies its data in the pre-render event: if (isDirty && ScriptManager1.IsInAsyncPostBack) { ScriptManager1.RegisterDataItem(this, CustomerList.SelectedValue, false); isDirty = false; } In this case, you re passing a plain string. Multiplepieces of data can be packed together using a JSON-encoded array. The nextscript shows how to retrieve this data at the end of a partial renderingoperation: function pageLoad(){ var manager =Sys.WebForms.PageRequestManager.getInstance(); manager.add_endRequest(OnEndRequest); }function OnEndRequest(sender, args) { var customerID =args.get_dataItems()["__Page"]; if (customerID) { preFetchUI(customerID); preFetchOrdersForCustomer(customerID); } } If dataItems returns an array, you then pick up thevarious elements using the familiar syntax of arrays: var items = args.get_dataItems()["__Page"]; var item1 = items[0]; In this particular example, the preFetchOrdersForCustomerfunction will use the ID to fire an async call to a Web service to obtain thelist of orders (see Figure 3). Two calls are made to the server, but they workasynchronously, which is good for the user and the system.
Figure 3: Data items used to fetchorders in advance. The sample code accompanyingthis article is available for download. Dino Esposito is amentor with Solid Quality Mentors (http://www.solidq.com)and specializes mainly in ASP.NET and AJAXsolutions. He s the author of IntroducingMicrosoft ASP.NET AJAX (Microsoft Press, May 2007) and wrote the twovolumes of Programming Microsoft ASP.NET 2.0,also for Microsoft Press. Late-breaking news is available at http://weblogs.asp.net/despos.
About the Author
You May Also Like