Saturday, December 10, 2011

The ASP.Net Postback Problem

Before we get into the meat of today's topic, I have a quick celebratory announcement: Things became legal today. I am now officially a partner in Rubicite Interactive. As of today I own 3% of the company - with a schedule in place for that amount to increase over the years so long as I remain with Rubicite. Huzzah!


Now then, back to our regularly scheduled topic. Last time, I discussed reasons that ASP.Net can make server-side interaction easier. There are some drawbacks. Using the javascript-driven update process, we control exactly which parts of the page are updated with our new data. This enables a more pleasant user experience by only having parts of the page reload when we make our changes. Unfortunately, this is not the standard behavior found with ASP.Net controls.

When you use an ASP.Net control and tie it to server-side code as we did in the previous article, any actions you take to execute your handling code must be run on the server. Put that way, it sounds obvious. The resulting implication is that each time your handling code is run, an HTTP POST is sent to the server, and the page is reloaded to reflect the current viewstate. All form elements are submitted as part of that POST request, and ASP.Net automatically refills each field of the form with the previous values before processing your handling code. The entire process is referred to as a postback.

A few things result from the postback process. First, users will see their entire page reload every time a postback occurs. In most situations, much of the page contents will be in cache, so the reload will not take as long as a normal page load. However, users are still likely to see the page flash, at the very least. From a user-interface enthusiast, this bothers me a bit.

The second result of the postback process is an interference with typical browser behavior. Since each postback is seen as a separate request by the browser, each one gets an entry in the browser history. This means that for each change of each server-side handled control, the browser will have a separate page in history. That's not too bad, until users start trying to use their browser's back functionality. Instead of moving back a page at a time as the user tends to expect, the user will have to press back for each change they made to each server-side handled control. For me, this type of user experience moves beyond being an annoyance and into a true issue.

To minimize these issues, one might choose to use standard HTML/javascript for all the elements that do not require server-side handling (e.g. if it doesn't have to interact with the database, keep it on the client-side). That way you minimize the impact to your users by avoiding the entire postback process for a lot of your actions. Most pages will seem more snappy that way. But it creates a slight complication in that the DOM elements resulting from ASP.Net controls are not as easy to interact with in your client-side code. By default, ASP.Net will adjust the ID of the elements generated for the controls to match an internal naming structure. This complicates the process of retrieving DOM elements through any kind of ID-based selector. Most of the time, that complication can be mitigated through use of the ClientIdMode="static" attribute within the ASP.Net control. Specifying this attribute will cause ASP.Net to use the exact ID that you specified for the DOM element it generates. The only place this falls apart is when the ASP.Net control generates more than one DOM element, as only the parent element will get the ID you specified. Even then, jQuery can come to the rescue through providing means to use parent/child selectors to nail down the exact DOM element you seek.

The choice to mix up implementation between standard HTML and ASP.Net controls feels a bit dirty to me. However, given the issues it helps with, I think it can be a valid choice. It certainly fits in the vein of incremental adoption that I like to think can work well. But it does create another problem, and it is perhaps the worst result of the postback process...

When a postback occurs, ASP.Net will automatically place the values for ASP.Net controls back into the related fields. If, however, you are using standard HTML form elements, they will not be given their previous values. A good way to deal with this is to set the default values for the HTML elements to be the result of the information pulled from the HTTP POST request. Since ASP.Net submits the form on each postback, these results will be available to load into the page each time. The only time this really fails miserably is when you already have a default value for a given element. Things get more complicated because you have to start tracking bits of state yourself in the code-behind (though often it is sufficient to set class variables with a default value and then update that variable with the result of the REQUEST variable, if it has a value).

This is all getting a bit hackish, but it works, and it enables you to get some of the benefits of both worlds. Still, you might be thinking that there has to be a better way to deal with the postback problem. In many situations, you would be right. Next time, I'll talk about using partial postbacks to make everything all better.

No comments:

Post a Comment