Wednesday, November 19, 2008

Cascading Dropdowns and 'Invalid postback or callback argument' error

Actually, I think this applies to any dynamic modification of drop down list options. Read on!

I have used a CascadingDropDown extender from the AjaxControlToolkit to select regions and provinces based on a web service. It was supposed to be painless and quick. And it was. Until another dev showed me a page giving the horribly obtuse '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.'. As you can see, this little error message basically says there is a problem with a control, but doesn't care to disclose which. There are no events or overridable methods to enable some sort of debug.

Luckily, Visual Studio 2008 has source debug inside the .Net framework itself. Thus I could see that the error is caused by the drop down lists I mentioned above. Google told me that somewhere in the documentation of the CascadingDropDown extender there is a mention on setting enableEventValidation to false. I couldn't find the reference, but of course, I didn't look too hard, because that is simply stupid. Why disable event validation for the entire page because of a control? It seems reasonable that Microsoft left it enabled for a reason. (Not that I accuse them of being reasonable, mind you).

Analysing further, I realised that the error kind of made sense. You see, the dropdownlists were not binded with data that came from a postback. How can one POST a value from a select html element if the select did not have it as an option? It must be a hack. Well, of course it was a hack, since the cascade extender filled the dropdown list with values.

I have tried to find a way to override something, make only those two dropdownlists not have event validation enabled. Couldn't find any way to do that. Instead, I've decided to register all possible values with Page.ClientScript.RegisterForEventValidation. And it worked. What I don't understand is why did this error occur only now, and not in the first two pages I have built and tested. That is still to be determined.

Here is the code

foreach (var region in regions)
new PostBackOptions(ddlRegions,region)

It should be used in a Render override, since the RegisterForEventValidation method only allows its use in the Render stage of the page cycle.

And that is it. Is it ugly to load all possible values in order to validate the input? Yes. But how else could you validate the input? A little more work and a hidden bug that appears when you least expect it, but now even the input from those drop downs is more secure.

My control was used in two pages with EnableEventValidation="false" and that's why it didn't throw any error. Anyway, I don't recommend setting it to false. Use the code above. BUT, if you don't know where the code goes or you don't understand what it does, better use this solution and save us both a lot of grief.


Nil said...


Good Post!!

But can you explain me
what is Regions in your code??

foreach (var region in regions)
new PostBackOptions(ddlRegions,region)

Siderite said...

It's a simple example. A drop down list with regions. The regions are strings. The point is that you should register each region as a possible value for a drop down item, or else the validation mechanism will throw an exception.

Devendra said...

thanks for the post .
if i have huge numbers like 4000 or more items then it will hit the performance.

what is the approach we need to follow at that time.

Siderite said...

Well, a dropdown, as I see it, is used to show a list of items, akin to a radiobutton or checkbox list (depending on multiple selection being disabled or enabled). It would be stupid to have 4000 items in a radiobutton list, it would stretch for 80 pages. But it is also silly to make a user scroll through 80 pages so 4000 items in a dropdown is something I would not condone. And you are telling me this is a cascading dropdown scenario, so you have 4000 items and when selecting one, more appear. That's insane!

My suggestion is to either use a more complex control, say a dynamic tree, or to split those 4000 items in two other dropdowns of 66 items.

But the best idea is to try to think like your user would think and imagine what would be the hassle of using your interface. And if it is too big, just change everything. You have the data in the database, but it is your job to bring it to the users so that is the least effort on their part to get to what they want.