Pains of the Postback

Making Postback Simple and Painless

Dino Esposito

October 30, 2009

10 Min Read
ITPro Today logo in a gray background | ITPro Today

CoreCoder

LANGUAGES: C#| VB.NET

ASP.NETVERSIONS: 2.0

 

Pains of the Postback

Making Postback Simple and Painless

 

By Dino Esposito

 

The postback mechanism is an essential part of ASP.NET.Simply put, it consists of posting form data to the same server page thatgenerated the present page with which the user is working. Once the contents ofthe present page are posted, a new page object is created and the view stateinformation is used to restore the call context that is, the same state ofcontrols existing when the posting page was last generated on the server.

 

After the page has been initialized and posted values havebeen taken into account, it s about time that some server-side events occur.There are two main types of events:

  • The first type of event signals that certaincontrols had the state changed over the postback.

  • The second type of event executes server code inresponse to the client action that caused the post.

 

The postback event involves some action on the client andthe server and sets some rules that, if not fulfilled, may raise exceptions andprovide unexpected behavior. In this article, I ll explore some of the issuesand common actions related to postback, especially on the client side. Inparticular, I ll examine the impact of JavaScript-driven page changes on thepostback mechanism, how to inject custom code in the submit process, and therole of the newest __EVENTVALIDATION hidden field.

 

Modifying Input Fields via Script

The growing use of script code in Web pages, and thegrowing level of standard Document Object Models (DOM) supported by browsers,makes it possible, and sometimes worthwhile, to use client script code tocomplete or modify the structure of the page. Let s consider a simple scenario:editing the contents of a TextBox using JavaScript. The following code showsthe involved ASP.NET page elements:

 

 Text="Defaultvalue" />  onclick="SetValue()" />   The JavaScript code to use is shown here:  function SetValue(){  var txt =document.getElementById("TextBox1");   txt.value = "Newvalue"; }   You execute the page and click the Set Value button toedit the value of the input field programmatically. Next, you click the submitbutton to post the current form to the server. When a submit action occurs, thebrowser correctly picks up the current value in the TextBox and sends it overthe wire to the server.   Inside the page lifecycle, the posted value is processedand used to update the state of the server-side counterpart of the TextBox.When the page has completed, the TextBox is configured to have the previouslyscripted value as its default value on the client. This behavior is notsurprising at all, and applies to text input fields as well as hidden fields.   Let s now consider a slightly different scenario in whicha brand new TextBox is created on the client that extends the page s DOM.  Creating New Input Fields via Script To create a new input text field, you run some JavaScriptcode and insert raw HTML in the current page s object model. Here s how to doit:  var markup = ""; document.getElementById("placeHolder").innerHTML +=markup;   The idea is that you prepare a string variable with therequired markup, then programmatically associate it with the inner HTML of aplaceholder tag; for example, a tag found in the original ASP.NETpage:

 

 

As Figure 1 shows, when the preceding code runs in aclient page a new TextBox is added to the page and is made ready for editing.

 


Figure 1: Adding a new TextBoxprogrammatically on the client.

 

Immediately after creating the new TextBox, you can alsoretrieve a reference and script it:

 

var newTextBox = document.getElementById("dynTextBox");

newTextBox.value = "Just added";

 

What if you click a submit button now and post back?Interestingly enough, here s the body of the HTTP packet being sent over thewire:

 

__VIEWSTATE=%2Fw...jz&

TextBox1=New+value&

Button2=Post+back...&

dynTextBox=Just+added&

__EVENTVALIDATION=%2Fw...Ykv

 

As you can see, the newly created TextBox is regularlypart of the post and retains its displayed value. However, when the page isre-rendered to the client, the newly added TextBox has disappeared. What s up?

 

Quite simply, ASP.NET attempts to find a match between theID of each posted element and server control. TextBox1, the sample TextBox weprogrammatically updated in the previous example, is part of the ASP.NET page,meaning that a reference to it is automatically created in the pageinitialization and easily found and updated with posted data.

 

The same doesn t happen for dynTextBox, which is completelyunknown on the ASP.NET side. Hence, ASP.NET ignores the posted data and stillrenders all and only the controls originally declared in the .aspx source file.

 

At this point, though, you might object that if I mcorrect here it would suffice to write some server code to programmaticallycreate a dynTextBox TextBox control during Page_Load to have the dynamicallycreated input field become officially part of the page and survive acrosspostbacks. Let s try it out.

 

You could retrieve programmatically the list of IDs withan entry in the Request.Form collection, but no matching control in the ASP.NETpage. Doing this will add an unnecessary layer of complexity here. For thisreason, I ll assume that the name of the dynamically created control is passedto the server using an ad hoc hiddenfield. (The hidden field is named HiddenField1 in this example.) Anotherassumption I m making here is that the dynamic control is a TextBox. Also, thiskind of information can be ferried to the server using the same hidden field inany format you like:

 

protected void Page_Load(object sender, EventArgs e)

{

  if(!String.IsNullOrEmpty(HiddenField1.Value))

  {

     // Assume valuecontains the ID of a TextBox

     string newControl =HiddenField1.Value;

     TextBox txt = newTextBox();

     txt.ID = newControl;

     this.Form.Controls.Add(txt);

  }

}

 

On the server, if the contents of the hidden field is notnull or empty, you create a new TextBox control, name it after the string inthe hidden field, and, finally, add the control to the Controls collection ofthe page s form. This additional step ensures that a matching control will befound for the dynTextBox posted field. As a result, the dynamic control shouldbe persisted across postbacks. If you run the page, click to create a new fieldas in Figure 1, and then post back, all that you get is the exception shown inFigure 2. The exception is because of an additional security barrier added inASP.NET 2.0 to prevent script injection attacks.

 


Figure 2: The Event Validationexception.

 

In brief, by default, each ASP.NET 2.0 page contains anextra hidden field named __EVENTVALIDATION that contains a snapshot of whichcontrols in the page should be validated during postbacks. More exactly, thehidden field lists which controls in the page can cause a postback and whichvalues can be posted. In the page displayed to the user, the event validationfield contains no information about dynTextBox. When the textbox is added andthe page posts back, nothing happens as long as the no-matching controlexists and the posted data is going to be ignored. But when you add a propercontrol that can handle the posted data, the control ID is checked against thecontents of the event validation field. Because dynTextBox is not there, theexception throws.

 

Before we get to learn a bit more about event validation,there s another aspect of textbox dynamic editing that is worthwhile to pointout. Imagine you have an ASP.NET TextBox control in the page and write some JavaScriptcode to let client users edit some of the control s properties other than thebuffered text. Suppose, for example, that you change the maximum length, theread-only state, or perhaps the background color of the textbox on the clientvia JavaScript. None of these property changes will ever be detected on theserver unless you explicitly manage to have these values ferried to the serverthrough a hidden field:

 

var txt = document.getElementById("TextBox1");

txt.value = "New value";

txt.style.backgroundColor = "yellow";

 

The background color is lost across postbacks unless youstore it in a hidden field, retrieve the value of the hidden field in thePage_Load event, and restore the property:

 

string color = HiddenField2.Value;

TextBox1.BackColor = ColorTranslator.FromHtml(color);

 

Inline Script vs. Custom Controls

Note that most of this code to manage client-side changesto HTML elements that are part of ASP.NET controls are better handled in customcontrols. In other words, if you want to be able to create textboxes dynamically,edit all properties on the client, and maintain these changes across postbacks,you are better off creating your own version of the TextBox control that emitsproper script code and exposes new properties to let page authors control whichfeatures should be enabled, and how. When it comes to moving to the server anycustom data collected on the client, hidden fields are the only way to go. Youemit hidden fields on a per-control basis (i.e., each client-creatable TextBoxwill have its own hidden field) and bind the two together using an arbitrarybut strong naming convention. Emitting a hidden field means that you call theClientScript s RegisterHiddenField method before rendering your custom control.

 

Next, using JavaScript, you record changes to the hiddenfield and process the hidden field contents on the server by implementing theIPostBackDataHandler interface on the new control. The format in which youwrite to the hidden field is completely up to you. At the cost of writing a bitmore management code, you could also consider using just one hidden field forall controls of a certain type.

 

Event Validation in ASP.NET 2.0

The ultimate goal of event validation in ASP.NET 2.0 isensuring that postback actions only originate from events supported and generatedby HTML elements that can be unequivocally associated with a well-known list ofserver controls. When each page is about to render, a list of server controlsthat support validation is created. In this list, you find the ID of thecontrol, as well as possible values it can post back. For example, both TextBoxand DropDownList support event validation, and both have their own ID stored inthe validation field. However, the DropDownList control also stores the list ofdisplayed values any of which can be selected and posted back. The same doesn thappen with textboxes because users can type any text into a textbox by design.

 

Information about event validation is serialized to ahidden field and incorporated in the client page, just like the classic viewstate.

 

When a postback occurs, the ASP.NET page uses the data inthe hidden field to verify that the sender of the event is a registered controland that any post is directed at registered controls and is, in the case of a listcontrol, registered data. If any of these checks fail, you get an exception (asshown in Figure 2). For example, if you add an option to a dropdown listdynamically using JavaScript, no exception is raised as long as the selectionis any of the originally displayed values. As the user selects the dynamicallyadded option and posts backs, the exception is thrown. Event validation isenabled by default and also raises an exception if the postback doesn t includea valid event validation field.

 

How can you work around the exception shown in Figure 2 ifyou legitimately need to create and inject controls on the client using JavaScript?The simplest, but also less secure, approach is disabling event validation.Event validation helps prevent spoofed requests, but if you feel relativelyconfident, disabling the feature might not be an option. You do that by settingthe EnableEventValidation attribute of the @Page directive to false:

 

<%@Page EnableEventValidation="false" %>

Another approach entails using a custom set of ASP.NET controlsdesigned to be editable and creatable on the client and capable of interactingwith the event validation subsystem in a custom way. But we ll save that foranother article.

 

The sample codeaccompanying this article is available for download.

 

Dino Esposito is aSolid Quality Learning mentor and the author of ProgrammingMicrosoft ASP.NET 2.0 Core Reference and ProgrammingMicrosoft ASP.NET 2.0 Applications-Advanced Topics, both from MicrosoftPress. Based in Italy,Dino is a frequent speaker at industry events worldwide. Join the blog at http://weblogs.asp.net/despos.

 

 

 

Sign up for the ITPro Today newsletter
Stay on top of the IT universe with commentary, news analysis, how-to's, and tips delivered to your inbox daily.

You May Also Like