ASP.NET Event Validation and “Invalid Callback Or Postback Argument” : Part II

Wednesday, March 22, 2006

In the last post we looked at the job event validation performs, and how we can trigger a validation error with some innocent JavaScript. If we receive exceptions because of event validation, we have to disable the feature, or learn how to work with the event validation.

Disable Event Validation

Pros: Easy to do
Cons: Less secure

Bertrand Le Roy wrote a post back in 2004: “Please, please, please, learn about injection attacks!”. Event validation is a feature designed to help prevent injection attacks (of course it can't prevent attacks all by itself).

We can disable event validation for an entire site in the web.config file.

<system.web>
   <
pages enableEventValidation="false"/>
</
system.web>

Alternatively, we can disable validation for a single page.

<%@ Page EnableEventValidation="false" ... %>

Register For Event Validation

Pros: Feel validated
Cons: We need to register all the legal post values before the page is sent to the client - this isn't always possible or practical

When we last left our application, we had a DropDownList with three legal values: “1”, “2”, or “3”. The problem was that client side script was adding a 4th option: “4”. If the user selected the 4th option and posted the form to the server, the server would throw an exception because it didn’t know “4” was a legal value.

The key to passing validation is to let ASP.NET know the value “4” is legal with the RegisterForEventValidation method of the ClientScriptManager class.

RegisterForEventValidation must be called during the rendering phase, so we need to override a Render method. We could start by overriding the Render method of our web form. Plug the following code right below the Page_Load method from the previous post.

protected override void Render(HtmlTextWriter writer)
{
   ClientScript.RegisterForEventValidation(
         _recipeList.UniqueID,
        
"4"
      );

  
base.Render(writer);
}

Remember event validation works by combining the hash of a control’s UniqueID property and a hash of each legal value for that control. The RegisterForEventValidation method accepts both of the calculation inputs as parameters. The method stores the result in a dictionary, and the page adds saves the dictionary as a hidden field on the client.

Adding the RegisterForEventValidation responsibility to the Page class is less than ideal, as the web form suddenly has to know about the DropDownList and its event validation problems. An alternate solution would be to build our own control.

using System;
using System.Web.UI.WebControls;
using System.Web.UI;

namespace OdeToCode.Web.UI.Controls
{
   [
SupportsEventValidation]
  
public class DynamicDropDownList : DropDownList
   {
      
protected override void Render(System.Web.UI.HtmlTextWriter writer)
      {
         Page.ClientScript.RegisterForEventValidation(
              
this.UniqueID,
              
"4"
            );
        
base.Render(writer);
      }
   }
}

A crucial step in the code is to add the SupportsEventValidation attribute to the class. If this attribute is not present, all the RegisterForEventValidation work is in vain. The runtime does not validate events for controls that do not have the SupportsEventValidation attribute present, nor does the runtime does look at the custom attributes of the control’s base class. The table of controls supporting event validation that appeared in the last post was output by a simple program that looped through all the Types in the System.Web assembly looking for the SupportsEventValidationAttribute.

In our example, we knew we only had one additional legal value – the value “4”. We need to call RegisterForEventValidation for every legal value the control might postback. This raises a couple issues because we may not know all of the legal values the control can take. AJAX might populate the control with values from a web service call that is bridged to a third party. Another issue is that the number of legal values might be extremely large.

Unfortunately, ASP.NET doesn’t expose a property to disable event validation for a single control – this would be a nice feature to have. However, if we create a custom control and leave off the SupportsEventValidation attribute, we’ll effectively disable event validation for instances of that class.


Comments
Sergio Pereira Wednesday, March 22, 2006
The attribute name itself suggest that it might be better off if it was an Interface instead. Then we could have ISupportsEventValidation.ValidationEnabled = false to supress validation for that control.
Scott Wednesday, March 22, 2006
Good point, Sergio.
Milan Negovan Monday, March 27, 2006
Excellent stuff, Scott! Thanks for taking time to document it.
David Grant Thursday, April 6, 2006
I just ran into this error two days ago, when trying to do a custom JavaScript postback to delete something.
thanks.
Andy Carlier Sunday, April 30, 2006
Phew. Was I glad to find this post. I have an AJAX postcode finder that has just fallen over. It's been working fine for months and then for no obvious reason I lose a Sunday morning to debugging! Thanks.
Songless Monday, May 1, 2006
Man you made my day!

I was having this problem with some AJAX stuff that places two input texts and submit button in a div container.

My first thought was: OK, when the page tries to process the POST data it can't find the new controls I added, so as a clever man I am :) I'm going to add the controls in the Page_Init event when proceeds.

It crashed again, and now I know what, the event validation engine doesn't wait those post values at all!!!
My postback validation pass but event validation fails miserably.

I have disabled the event validation in the <pages /> section. But I agree the ideal solution would be to enable it in a control-basis. Thanks !!!
Chris Wilson Monday, June 5, 2006
This page, as well as part I, made a perplexing problem very clear and provided a good solution. Your page was the first and only one I found that knew about the [SupportsEventValidation] tag, and creating a derived version of ListBox that didn't have the tag turned out to be a good workaround. Thanks for your effort!
Martin Wednesday, July 26, 2006
Hello, helpful as it is about what you said, you didn't address the problem you mentioned when a dropdownlist becomes populated at runtime? or worse than that when a control is created at runtime on Page_Load?

how should I do that?
Thanks
scott Wednesday, July 26, 2006
Martin:

As long as the control building takes place on the server you should be ok. It's only when a value appears that wasn't in the control on the server side that there is a problem, I believe.
Martin Wednesday, July 26, 2006
oh yes thanks for the answer

So lets say I have an ImageButton building on at runtime on Page_Load adding attributes such as CallbackReference. When selecting one of these ImageButton a (or more) DropDownList are filled in with the Callback process using Javascript!

Shouldn't I have any problems? So EventValidation is not needed here or what?
scott Wednesday, July 26, 2006
Well, you are safe if the control loads the values on the server - but if you are populating a dropdownlist with javascript on the client, that is when event validation will trip you up. You can use the steps above to register all the possible values for the dropdownlist.
Martin Wednesday, July 26, 2006
I'm using Callback so I have to use javascript on the client to populate a dropdownlist with values calculated from the server.

so for each value that can be populated I have to register it with RegisterForEventValidation ?
I'm still getting the idea of how to use this RegisterForEventValidation when you have controls that are built on runtime and are populated dynamically!

the above example is when you know the items of the dropdownlist .. but when you don't?
scott Wednesday, July 26, 2006
Oh, I think I see where you are coming from.

You are populating the list with values using javascript, but you don't know what the possible values will be? Are the values coming from stuff the user types into the web page?

If that is the case you'll have to disable event validation for the page, or derive a new control from DropDownList like in the example above, but leave off the SupportsEventValidation argument.
Martin Wednesday, July 26, 2006
thanks for your patience btw :) and sorry for my poor english..

the values are coming from a database according to the number of ImageButton clicked. Each ImageButton has an CallbackReference and when click a dropdownlist is filled with data from the database...
scott Wednesday, July 26, 2006
Ah, I see. I don't think you can use RegisterForEventValidation during a callback, at least I don't think it would change the behavior (I could be wrong).

I think you'll have to disable event validation.

Your english is fine, I was just slow to understand the problem.
Martin Wednesday, July 26, 2006

but I would have a security breach in my web page or not? I could easily make it false EventValidation on Page start but what about security?
Martin Wednesday, July 26, 2006
Also, I have a textbox and in this a user can enter a number from 1 to 1000, how can I validate that?
scott Thursday, July 27, 2006
For the TextBox use a RequiredFieldValidator and a RangeValidator.

For the DropDownList you can always compare the incoming value against the legal values in your database.
Martin Thursday, July 27, 2006
but I would have a security breach in my web page or not? I could easily make it false EventValidation on Page start but what about security?

the Textbox entry is not always required by the user.

to the Dropdownlist it is a solution (compare with db) although I thought I can make use of the RegisterForEventValidation
scott Thursday, July 27, 2006
You can always parse the textbox and make sure it is in the require range if the user entered it. Just be careful with user input (read Bertrand's post - the link at the top of this post).
Nate Monday, November 6, 2006
If anyone happens to see this:

I made a page where I created a control that overrides dropdownlist. I place it on the page using the placeholder control. Now, I do this because I'm dynamically adding options to the dropdown using javascript as described here in this article. The thing is:

When I postback (hitting a button), I am unable to see the currently selected value in the dropdown. Is there a way to communicate the selectedValue during the postback?
Jered Friday, November 10, 2006
Good Post. I'd like to add that it is much easier to debug this error (especially when you are doing something more complex than adding a value to a dropdown) if you override the RaisePostBackEvent method on the page and add a breakpoint in the method. This way you can see what is being passed to the ValidateEvent method and know what exactly to pass to the RegisterEventForValidation method.

protected override void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument)
{
string strArgs = eventArgument;
base.RaisePostBackEvent(sourceControl, eventArgument);
}
Alex Wednesday, November 15, 2006
I have the invalid callback problem, but not because of client side scripts changing the state of server side controls.

It occurs simply because, with a slow connection, I can raise a postback before the page has fully loaded - e.g.

- User links to the ASP.NET page, page loads fully.
- User clicks a button, and the page transfers.
- User realises they've made a mistake, and quickly clicks another button, just as the page is half-loaded in the browser.
- Error page appears.

I guess there's not really a decent way to get round this, it's fairly obvious that only sending back half the page will generate a validation error.

Any suggestions?
come from china Thursday, December 7, 2006
I didn't write any Scripts but this error still occurs when i click a Image of a CommanField of a GridView.
can anyone help me ?
Thanks
ZLA Friday, December 15, 2006
Thank you so much. I created a double list box to select / remove items from one to the other. Since I know all the possible values, it was easy to just add all the items from one list to the other.
Logan Thursday, January 4, 2007
I am having the same problem that Alex is having. I have a listbox that has multiple items listed inside. When the user clicks on the items it adds the item to a order. Before the page is fully refreshed, progress bar still active but items are there to click if the user clicks again I get this error. Very simular to what Alex is seeing. Any ideas?
ARSP Wednesday, January 17, 2007
Thank you so much for this post.
I designed a custom GridView by template field
and add an ImageButton to it,at run time when i press button "invalid postba..." exception was triggered,but girdview just show data and no modified data ,no new data ,no script,...
just when button clicked the page redirected to oder page with a query string.
but i still have problem!
<asp:ImageButton runat="Server" ID="btnBuy"
CommandName="Buy" CommandArgument='<%#EVAL("ID")%>'/>
can anyone help me?
gravatar Nishant Sagar Friday, June 4, 2010
I am also facing the same problem as posted by Nate at 11/6/2006 11:08 PM. Please help for the workaround.
gravatar Rajesh Tuesday, September 7, 2010
I fixed the problem by using the code in my render method,

Page.ClientScript.GetPostBackEventReference(textbox1, "", true);

Hope this helps some one in need
gravatar Diya Tuesday, January 11, 2011
But if i set false it may be difficult for another controls..
BAM Friday, January 21, 2011
Scott,

You wrote:
A crucial step in the code is to add the SupportsEventValidation attribute to the class. If this attribute is not present, all the RegisterForEventValidation work is in vain. The runtime does not validate events for controls that do not have the SupportsEventValidation attribute present, nor does the runtime does look at the custom attributes of the control’s base class.

I tried to prevent the Event Validation error by extending DropDownList and leaving off the SupportsEventValidation attribute. It did not prevent the error.

Did I miss something?
BAM Friday, January 21, 2011
Your code works completely as advertised. I was making a stupid mistake.

Thank you very much for an excellent post.
Comments are now closed.
by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!