Tuesday, September 25, 2007

Many people find it mysterious when they get a message box with the following error message:

Invalid postback or callback argument. Event validation is enabled using <pages enableEventValidation="true"/> in configuration or <%@ Page EnableEventValidation="true" %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.

Unfortunately ASP.NET does not provide enough information to troubleshoot this exception easily. I am going to explain reasons that can cause this exception and give a tip on how to troubleshoot it.

The event validation is designed to prevent malicious requests from breaking your software. When a server page is rendered and sent to the browser web controls tell ASP.NET about all allowed values that the web page can submit back to the server. The collected values are hashed and stored in the hidden input in the web page. When the postback values are received from the client postback values are validated against the hashes stored in this hidden input.

If server encounters any value with a hash which is among hashes in the __EVENTVALIDATION field it throws an exception with the message above. If you develop with pure ASP.NET and receive such exception it usually means that someone attempts to tamper a request and does it incorrectly.

With the ASP.NET AJAX extensions however it becomes possible to get this exception as a result of developer mistake.

I've constructed a sample which demonstrates what you have to do (really you should not do) to get this weird message box.

If you run this sample and click the button twice you will see exactly the same message box. So, what is causing ASP.NET to throw an exception in the sample above?

The sample changes items in the DropDownList on each postback and changes them in a way that previously selected item disappears from the list on the next postback. (Similar things happen if you implement cascading dropdowns with autopostbacks). If you disable partial rendering by setting ScriptManager property

EnablePartialRendering="false"

you will see that the page works perfectly. DropDownList tells ASP.NET about all values in the items collection while it is been rendered and ASP.NET successfully validates submitted value against hashes stored in the "event validation" hidden input on the next postback. If you re-enable partial rendering in this sample, one small but still important thing changes. Render method of the DropDownList is still invoked on every postback, but output of the render method is not sent to the browser, because it is in the UpdatePanel which is not updated in response to button click. (I intentionally made button to cause the asynchronous postback without updating second UpdatePanel). Now, __EVENTVALIDATION hidden input is successfully updated with new hash values for DropDownList, but the DropDownList itself remains unchanged on the client and still submits old selected value on the next postback. When the server receives this value it cannot validate it against the new set of hashes in the "event validation" hidden input and throws he exception.

So, the conclusion is very simple: "Don't change controls during the async postback that are outside an update panel or are in the update panel which is not updated during this asynchronous postback." Or vice versa: "If you have conditional update panels force them to update their client state if you change controls inside the update panel." (See commented code in the sample and try uncommenting it).

Start your web site under the debugger and reproduce the exception (you may get some other internal ASP.NET exceptions while starting the website - click "continue" until you get the "event validation failed" exception

Click on break button and open "call stack" tool window

The selected stack frames on the following screen-shot tells you that the problematic control is DropDownList

Unfortunately it is not always possible to find what particular control causes the exception, but for DropDownList it is typically possible to do. Double click the DropDownList.LoadPostData stack frame and open "Locals" debug tool window. You should be able to expand "this" value. (I don't know if you can find a stack frame with accessible this variable for other controls. )

The final step is to get the UniqueID of the failing control. Just open a QuickWatch and type UniqueID there.

Now when you know which controls causes the problem you should check:

whether you change properties of this controls and whether you need to change them. If so,

whether this control is in the update panel and whether this update panel is updated during the asynchronous postback

More Cases Causing the Same Problem

DropDownList must not be in the update panel to cause the problem. It is enough to change its Items collection during asynchronous postback.

Do you know other ways to get this exception with Microsoft ASP.NET AJAX Extensions?

I might add that my problem was a bit unexpected. I had a page with an updatepanel containing some controls and a hidden field outside of it. The hidden field had viewstate disabled, and therefore lost its value on partial postback in the updatepanel. When the controls posted back a second time, event validation failed for the hidden field!/M

I am also getting a very unusual error. Please see if you can help me in debugging this.I have a page with an updatepanel contol which contains a dropdown user control. On partial postbak the "Page Title" changes from "Website®" to "Website®"....It is not taking the special character symbol after post back.What could be the problem in my code. I would appreciate if ou can guide me.Thanks