Vous êtes sur la page 1sur 7

Wicked Code: UpdatePanel Tips and Tricks http://msdn.microsoft.com/en-us/magazine/cc163413.

aspx

Internet Explorer 8 - faster, safer, easier

United States - English Sign in


MSDN Magazine Search MSDN Magazine with Bing

Home Current Issue Topics Issues Columns Downloads Subscribe Contact Us

MSDN Magazine > Issues > 2007 > June > Wicked Code: UpdatePanel Tips and Tricks

Wicked Code

UpdatePanel Tips and Tricks


Jeff Prosise

Contents
Update Highlighting
Canceling UpdatePanel Updates
Multiple UpdatePanels
Updates without UpdatePanels
Web Service != SOAP and XML

For better or for worse, the UpdatePanel control is the darling of the ASP.NET AJAX community. I say "for
better" because UpdatePanel makes partial-page rendering shockingly easy and "for worse" because its
simplicity and ease-of-use come at the cost of efficiency and, ironically, bandwidth.
While UpdatePanel brings AJAX magic to ordinary Web pages, it doesn’t bring the efficiency we normally
associate with AJAX. Did you know, for example, that when an UpdatePanel control performs an asynchronous
AJAX callback to the server to update its content, the request contains everything a conventional ASP.NET
postback contains, including view state? Most developers assume that AJAX eliminates view state. That’s not
the case, though, with UpdatePanel’s brand of AJAX.
If you’re going to use an UpdatePanel control, you need to know what you’re getting in to. In many cases, from
a performance point of view, an application is better off not using UpdatePanel and instead using
asynchronous calls to WebMethods or page methods. Doing so can reduce the volume of data traveling over
the wire by an order of magnitude or more. However, it’s also a fundamental shift where the UI updates need
to be handled explicitly by the developer with JavaScript in the page.
In addition, ASP.NET AJAX discussion forums are already filled with questions about customizing UpdatePanel.
Many of these questions are easily answered once you know about PageRequestManager, the JavaScript class
in the Microsoft® AJAX Library that provides the client-side support for UpdatePanels.
Now that ASP.NET AJAX has shipped, I’d like to examine UpdatePanel more closely—taking a close look at
how you can customize it, optimize it, and even live without it. And that’s exactly what this column is all about.
Current Issue
Update Highlighting
Sometimes you can’t help but feel sorry for the developers at Microsoft. If they don’t do their job well enough,
they get pounded by the public. However, they sometimes also get slammed if they do their job too well. For
example, I recently got e-mail from a customer complaining that the ASP.NET AJAX UpdatePanel works a little
too well.
UpdatePanel makes it extremely easy to take all that flashing and flickering that occurs when an ASP.NET page
posts back to the server and turn it into smooth, flicker-free updates. UpdatePanel works its magic by
converting postbacks into asynchronous callbacks (XML-HTTP requests) and using JavaScript on the client to
refresh the part of the page encapsulated by the UpdatePanel control. The flashing and flickering goes away
because the browser doesn’t repaint the page as it does during a postback.
The customer’s complaint was that users were sometimes not noticing that part of the page had been updated
with new content. His question was simple: can the folks on the ASP.NET AJAX team make UpdatePanel flicker
just a little so important updates won’t be missed?
The bad news is that the ASP.NET AJAX team probably isn’t interested in making UpdatePanels flicker. After all,
getting rid of the flicker is why UpdatePanel was invented in the first place. The good news is that you can Browse All MSDN Magazines
work a little AJAX magic in the browser to draw attention to updated UpdatePanels. The secret is the
Sys.WebForms.PageRequestManager class in the Microsoft AJAX Library—the library of JavaScript classes that
comprise the client half of ASP.NET AJAX. PageRequestManager manages the asynchronous callbacks
launched by UpdatePanel. It’s also responsible for updating the content inside an UpdatePanel when an
asynchronous callback completes.
PageRequestManager fires events in the browser before and after an update occurs. You can hook these
events in JavaScript and run code that draws a user’s attention to the updated content. The key event is named
pageLoaded. This event fires each time the page loads in the browser (it’s analogous to Page_Load in
ASP.NET). It also fires each time an asynchronous callback launched on behalf of an UpdatePanel control
completes and the content inside that UpdatePanel is updated. You can register a JavaScript handler for the
pageLoaded event with two lines of code (which can be combined into one):

var prm = Sys.WebForms.PageRequestManager.getInstance();


prm.add_pageLoaded(pageLoaded);

The first line acquires a reference to the page’s PageRequestManager object. The second registers a JavaScript
function named pageLoaded as a handler for pageLoaded events.
When called, a pageLoaded event handler receives an argument of type Sys.WebForms.PageLoadedEventArgs,
which is another class in the Microsoft AJAX Library. PageLoadedEventArgs contains a get_panelsUpdated
method that you can call to enumerate all the UpdatePanels, if any, whose content was just updated. By

1 of 7 11/5/2010 7:32 PM
Wicked Code: UpdatePanel Tips and Tricks http://msdn.microsoft.com/en-us/magazine/cc163413.aspx

default, an UpdatePanel is nothing more than a DIV on the client-side so you can use JavaScript to flash the
DIV, highlight it, or do whatever you want to do to draw a user’s attention to it.
The code listed in Figure 1 shows one way to use pageLoaded events to perform update highlighting. Each
time an update occurs, this JavaScript flashes the Document Object Model (DOM) elements representing
updated UpdatePanels by making them appear and disappear three times in quick succession. The flashing is
performed by a helper function named flashPanels, which takes a flash count as an input parameter.

Figure 1 Flashing Updates

<script type=”text/javascript”>

var prm = Sys.WebForms.PageRequestManager.getInstance();


prm.add_pageLoaded(pageLoaded);

var _panels, _count;

function pageLoaded(sender, args)


{
if (_panels != undefined && _panels.length > 0)
{
for (i=0; i < _panels.length; i++)
_panels[i].dispose();
}

var panels = args.get_panelsUpdated();

if (panels.length > 0)
{
_panels = new Array(panels.length);

for (i=0; i < panels.length; i++)


_panels[i] = new Sys.UI.Control(panels[i]);

flashPanels(3);
}
}

function flashPanels(count)
{
_count = (count << 1) + 1;

for (i=0; i < _panels.length; i++)


_panels[i].set_visible(false);

window.setTimeout(toggleVisibility, 50);
}

function toggleVisibility()
{
for (i=0; i < _panels.length; i++)
_panels[i].set_visible(!_panels[i].get_visible());

if (--_count > 0)
window.setTimeout(toggleVisibility, 50);
}
</script>

Note how an updated UpdatePanel’s visibility is toggled on and off to create a flashing effect. Rather than
interacting with DOM elements directly, the code wraps the DOM elements representing the UpdatePanels
with Sys.UI.Control objects. Then it uses Sys.UI.Control’s set_visible and get_visible methods to toggle the
visibility:

_panels[i].set_visible(!_panels[i].get_visible());

Sys.UI.Control is a JavaScript class found in the Microsoft AJAX Library—specifically, in MicrosoftAjax.js. The
benefit to toggling visibility in this manner is that this is browser-independent. This works equally well in every
browser that supports ASP.NET AJAX (which is virtually all modern browsers). JavaScript code that interacts
directly with the browser DOM, on the other hand, would have to be tweaked to work in different browser
types.

Canceling UpdatePanel Updates


The pageLoaded event is one of several events that the PageRequestManager class fires when an UpdatePanel
goes back to the server to update its content. Another important event that PageRequestManager fires is
initializeRequest, which fires before an asynchronous callback occurs.
Someone recently asked me whether it’s possible to decide at runtime whether an AsyncPostBackTrigger
should be allowed to trigger an UpdatePanel update. The answer is yes. This is done by processing
initializeRequest events.
The second parameter passed to an initializeRequest handler is an object of type initializeRequestEventArgs.
That object contains a get_postBackElement method that identifies the button or other element that triggered
the update. It also has a set_cancel method that you can use to cancel a callback before it occurs. Here’s an
example of the set_cancel method in action:

2 of 7 11/5/2010 7:32 PM
Wicked Code: UpdatePanel Tips and Tricks http://msdn.microsoft.com/en-us/magazine/cc163413.aspx

<script type=”text/javascript”>

var prm = Sys.WebForms.PageRequestManager.getInstance();


prm.add_initializeRequest(initializeRequest);

function initializeRequest(sender, args)


{
args.set_cancel(!confirm(‘Are you sure?’));
}
</script>

In this sample, before a callback executes, an intializeRequest handler pops up a confirmation box asking the
user whether the update should proceed. Clicking Cancel in the confirmation box passes true to set_cancel,
which stops the callback in its tracks. In real life, you probably aren’t interested in prompting the user for
confirmation before allowing an update to proceed, but it might be useful to have the ability to cancel an
update based on conditions elsewhere in the application.
Incidentally, it’s also possible to cancel asynchronous callbacks after they’ve been executed but before they’ve
completed. PageRequestManager provides an abortPostBack method for doing this; it also provides a
get_isInAsyncPostBack method for determining whether an asynchronous callback is pending. These methods
are often used with UpdateProgress controls to present a cancellation UI.

Multiple UpdatePanels
A page can host several UpdatePanels. By default, when one UpdatePanel on a page updates, the other
UpdatePanels on the page also update. Sometimes that’s what you want, but more often than not, you don’t
need every UpdatePanel updating in response to other UpdatePanels.
You can be selective about which UpdatePanel instances update (and when) by setting the UpdateMode
property of each UpdatePanel control on the page to "Conditional." Then, when one UpdatePanel updates and
calls a server-side event handler, call UpdatePanel.Update on the other panels you want to update. This
reduces the load on the server by reducing the number of controls that render, and it reduces the volume of
data in the response because UpdatePanels that don’t update don’t add anything to the response.

Updates without UpdatePanels


AJAX isn’t just about creating a better user experience—it’s also about delivering greater efficiency on the
wire. When a traditional ASP.NET postback occurs, all the data in the Web form, including view state, travels
up to the server in the postback. View state is one reason ASP.NET pages, especially ones that use DataGrid
and GridView controls, can seem sluggish. Pages with too much view state are a bane to performance—and
pages with too much view state are all too common in ASP.NET applications.
One of the benefits of replacing ASP.NET postbacks with AJAX callbacks is that, done properly, AJAX callbacks
transmit only the data that needs to be transmitted. This means they do not have to include view state in that
transmission.
When you use UpdatePanel to perform flicker-free updates on a page, you may think you’re building in
efficiency. After all, UpdatePanels use AJAX, right? Unfortunately, if you check out the traffic on the wire when
an UpdatePanel updates, you’ll find you’re not saving much at all—at least not in the send. The View state
data (and other data) that’s normally transmitted to the server during a postback is also transmitted during
UpdatePanel callbacks. In fact, what goes up in an asynchronous XML-HTTP request from an UpdatePanel is
almost identical to what goes up in a standard ASP .NET postback. Here’s the dirty little secret about ASP.NET
AJAX: UpdatePanel is about ease of use, not efficiency on the wire.
There’s little you can do to make UpdatePanels more efficient, but you can forego the use of UpdatePanels
and use other features of ASP.NET AJAX to update content on pages just as smoothly and much more
efficiently. It takes a little more work, but the results are often worthwhile since you can dramatically reduce
the volume of data traveling between the client and the server.
You can also reduce the load on your server. When an UpdatePanel calls back to the server, the page targeted
by the callback goes through an almost complete lifecycle—the page is instantiated, the controls in the page
are instantiated, and controls inside the UpdatePanel undergo a normal rendering cycle. That’s a lot of
overhead just to update a portion of the page.
As an example, consider the page fragment in Figure 2. It provides a simple UI that allows the user to type in a
ZIP Code and click a button to initialize the city and state fields with a city and state (see Figure 3). All the
controls are hosted in an UpdatePanel, so the Button control’s postback is converted into an asynchronous
callback and the event handler (GetCityAndState) is called on the server inside the callback. GetCityAndState
(the code isn’t shown) reads the ZIP Code from the ZIP Code TextBox, converts it into a city and state, and
initializes the TextBox and DropDownList representing the city and state, accordingly. Since this all happens
inside an UpdatePanel, the update is smooth and flicker-free.

Figure 2 Filling City and State Fields with an UpdatePanel

3 of 7 11/5/2010 7:32 PM
Wicked Code: UpdatePanel Tips and Tricks http://msdn.microsoft.com/en-us/magazine/cc163413.aspx

<asp:UpdatePanel ID=”UpdatePanel1” runat=”server”>


<ContentTemplate>
City:<br />
<asp:TextBox ID=”City” runat=”server” />
<br /><br />
State:<br />
<asp:DropDownList ID=”Region” runat=”server”>
<asp:ListItem Value=”AL”>Alabama</asp:ListItem>
<asp:ListItem Value=”AK”>Alaska</asp:ListItem>
<asp:ListItem Value=”AZ”>Arizona</asp:ListItem>
...
<asp:ListItem Value=”WV”>West Virginia</asp:ListItem>
<asp:ListItem Value=”WI”>Wisconsin</asp:ListItem>
<asp:ListItem Value=”WY”>Wyoming</asp:ListItem>
</asp:DropDownList>
<br /><br />
Zip Code:<br />
<asp:TextBox ID=”ZipCode” runat=”server” />&nbsp;
<asp:Button ID=”AutofillButton” Text=”Autofill”
OnClick=”GetCityAndState” runat=”server” />
</ContentTemplate>
</asp:UpdatePanel>

Figure 3 City, State, and ZIP Code UI (Click the image for a larger view)
Here’s the problem. An UpdatePanel used this way improves the user experience, but it does little to reduce
the volume of data being passed over the wire. The UpdatePanel hardly reduces the load on the server,
either—up to the point that the controls inside the UpdatePanel render, the processing performed on the
server is almost identical to what happens during a full-blown postback. It has to be this way because one of
the benefits of the UpdatePanel control is that server-side event handlers like GetCityAndState work no
differently inside an asynchronous callback than they do in a traditional postback. That means controls on the
page have to be instantiated, they have to be initialized, they have to have access to view state, and so on.
Figure 4 demonstrates how to implement the same functionality without an UpdatePanel control. This time,
the Autofill button is wired to a bit of JavaScript that fires off an asynchronous XML-HTTP request to an ASMX
Web method named GetCityAndState. The call is placed through the JavaScript proxy named ZipCodeService,
which is generated by the service reference in the ScriptManager control. GetCityAndState takes a ZIP Code
string as input and returns a string array containing two items: the corresponding city and state. The
completion function onGetCityAndStateCompleted retrieves the items from the array and inserts them into the
city and state fields. Same result on the outside, but a very different way of going about it on the inside.

Figure 4 Filling City and State Fields without an UpdatePanel

4 of 7 11/5/2010 7:32 PM
Wicked Code: UpdatePanel Tips and Tricks http://msdn.microsoft.com/en-us/magazine/cc163413.aspx

<asp:ScriptManager ID=”ScriptManager1” runat=”server”>


<Services>
<asp:ServiceReference Path=”ZipCodeService.asmx” />
</Services>
<Scripts>
<asp:ScriptReference Name=”PreviewScript.js”
Assembly=”Microsoft.Web.Preview” />
</Scripts>
</asp:ScriptManager>

City:<br />
<asp:TextBox ID=”City” runat=”server” />
<br /><br />
State:<br />
<asp:DropDownList ID=”Region” runat=”server”>
<asp:ListItem Value=”AL”>Alabama</asp:ListItem>
<asp:ListItem Value=”AK”>Alaska</asp:ListItem>
<asp:ListItem Value=”AZ”>Arizona</asp:ListItem>
...
<asp:ListItem Value=”WV”>West Virginia</asp:ListItem>
<asp:ListItem Value=”WI”>Wisconsin</asp:ListItem>
<asp:ListItem Value=”WY”>Wyoming</asp:ListItem>
</asp:DropDownList>
<br /><br />
Zip Code:<br />
<asp:TextBox ID=”ZipCode” runat=”server” />&nbsp;
<asp:Button ID=”AutofillButton” Text=”Autofill”
OnClientClick=”autoFill(); return false;” runat=”server” />

<script type=”text/javascript”>
function autoFill()
{
var tb = new Sys.Preview.UI.TextBox ($get(‘ZipCode’));
var zip = tb.get_text();

if (zip.length == 5)
ZipCodeService.GetCityAndState (zip,
onGetCityAndStateCompleted);
}

function onGetCityAndStateCompleted(result)
{
if (result != null)
{
var tb = new Sys.Preview.UI.TextBox ($get(‘City’));
tb.set_text(result[0]);

var select =
new Sys.Preview.UI.Selector ($get(‘Region’));
select.set_selectedValue(result[1]);
}
}
</script>

Here’s how the ASMX Web method called through the JavaScript proxy is implemented:

[ScriptService]
public class ZipCodeService : System.Web.Services.WebService
{
[WebMethod]
public string[] GetCityAndState(string zip)
{
...
}
}

This is a standard Web method in every respect except for the fact that the class to which it belongs is
attributed ScriptService instead of WebService. ScriptService is synonymous with WebService, but it carries the
added meaning that the Web service’s WebMethods are callable from client-side script.
In addition to allowing conventional WebMethods to serve as targets for XML-HTTP requests, ASP.NET AJAX
also supports a special type of Web method known as the page method. Page methods are WebMethods
implemented in Web pages—that is, in ASPX files or codebehind files rather than in ASMX files. Page methods
allow developers to provide endpoints for XML-HTTP callbacks without building dedicated Web services.
Page methods must be public static methods and, like WebMethods, must be decorated with the WebMethod
attribute. (WebMethods and page methods can also be decorated with the ScriptMethod attribute, which
provides added control over what goes out over the wire.) On the client, page methods are called from
JavaScript through the special PageMethods proxy.
Unlike Web services, page methods do not require service references. However, you do have to enable page
methods by setting a ScriptManager control’s EnablePageMethods property to true, like so:

5 of 7 11/5/2010 7:32 PM
Wicked Code: UpdatePanel Tips and Tricks http://msdn.microsoft.com/en-us/magazine/cc163413.aspx

<asp:ScriptManager ID=”ScriptManager1” runat=”server”


EnablePageMethods=”true” />

Under the hood, page methods offer the same efficiency as WebMethods. View state and other input is not
transmitted to the server when page methods are called. And since page methods are static, they can be called
without instantiating a page object. A call to a page method does not invoke the page lifecycle that is
triggered by conventional ASP.NET requests.

Web Service != SOAP and XML


One of ASP.NET AJAX’s most important features is the ability to invoke WebMethods and page methods on a
server using asynchronous XML-HTTP requests from browser clients. Yet when I tell people about this feature,
I can’t help but cringe just a little.
When most of us hear the term Web service, we think about SOAP and XML. Neither of these technologies is
typically mentioned in the same sentence as the word efficient. Yes, you can call WebMethods from JavaScript
using ASP.NET AJAX. But no, ASP.NET AJAX doesn’t use SOAP and XML.
Figure 5 shows what travels over the wire when the Web method call in Figure 4 is executed. Other than the
HTTP headers, the only data transmitted in the request is the ZIP Code that the user typed, and the only data
returned in the response is a pair of strings representing a city and state. You won’t see any SOAP or XML (or
view state, for that matter). Instead, input and output is encoded using JavaScript Object Notation (JSON),
which is much less verbose than XML and easier to process. Rather than SOAP, the request and response use a
simple protocol that is basically just HTTP. The combination of HTTP and JSON makes ASP.NET AJAX calls to
WebMethods and page methods much more efficient than traditional Web service calls.

Figure 5 JSON-Encoded Input and Output

Request

POST /Ajax/ZipCodeService.asmx/GetCityAndState HTTP/1.1


Accept: */*
Accept-Language: en-us
Referer: http://localhost:1997/Ajax/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 is an up-and-coming industry-standard serialization format. It’s also the native format employed by
ASP.NET AJAX. JSON serialization and deserialization support is provided on the client-side by the Microsoft
AJAX Library’s Sys.Serialization.JavaScriptSerializer class. On the server, support is provided by the
System.Web.Script.Serialization.JavaScriptSerializer class.
Not all types are JSON-compatible. JSON cannot, for example, handle objects with circular references. When
you need to return complex data types that aren’t JSON-compatible, you can actually use ASP.NET AJAX’s
ScriptMethod attribute to serialize return types into XML. This technique is also useful for methods that return
XML data, as demonstrated here:

[ScriptMethod (ResponseFormat=ResponseFormat.Xml)]
public XmlDocument GetData()
{
...
}

Alternatively, you can build and register custom JSON converters that allow types that aren’t normally
JSON-compatible to be serialized and deserialized. The ASP.NET AJAX January Futures CTP contains three
such converters: one for DataSets, one for DataTables, and one for DataRows.

Send your questions and comments for Jeff to wicked@microsoft.com.

6 of 7 11/5/2010 7:32 PM
Wicked Code: UpdatePanel Tips and Tricks http://msdn.microsoft.com/en-us/magazine/cc163413.aspx

Jeff Prosise is a contributing editor to MSDN Magazine and the author of several books, including
Programming Microsoft .NET (Microsoft Press, 2002). He’s also a cofounder of Wintellect
(www.wintellect.com), a software consulting and education firm that specializes in Microsoft .NET.

© 2010 Microsoft Corporation. All rights reserved. Terms of Use | Trademarks | Privacy Statement | Site Feedback

7 of 7 11/5/2010 7:32 PM

Vous aimerez peut-être aussi