Joseph Rattz emailed me about posts I wrote last year covering ASP.NET event validation (see ASP.NET Event Validation and "Invalid Callback Or Postback Argument" Part I and Part II). In the posts I describe one scenario where an event validation exception can appear, and describe how to prevent the exception. In the scenario, client side script dynamically adds values to a list (select) control. When the user POSTs the form to the server, ASP.NET sees a new value and concludes something is wrong. The list comes back to the server with a value that wasn't present when the list left the server. ASP.NET tracks the legal values by serializing them into a hidden input control with an ID of __EVENTVALIDATION. This event validation feature helps to prevent all sorts of form spoofing attacks.
Joe's scenario was odd, not only because the invalid postback argument exception appeared sporadically, but because the source of the exception was a TextBox control!
ArgumentException: Invalid postback or callback argument. ... System.Web.UI.ClientScriptManager.ValidateEvent(..) ... System.Web.UI.Control.ValidateEvent(..) ... System.Web.UI.WebControls.TextBox.LoadPostData(..) ...
What could ASP.NET possibly validate about a TextBox? A server can expect specific values from a DropDownList, but a plain TextBox allows free form text entry by the user. The answer (via Reflector), is that the TextBox control only validates that its UniqueID is present in the legal arguments described by the __EVENTVALIDATION data. Even after knowing this information, it's hard to see what could go possibly wrong with a TextBox.
Joe's theory, which I believe to be correct, is that the user might create a postback before their browser even receives the __EVENTVALIDATION form input. This could happen, for example, over a poor connection. The resulting POST won't contain the __EVENTVALIDATION input, and thus ASP.NET cannot validate the postback arguments. The klaxons wail. Glass breaks. The runtime throws an exception.
One way to validate this theory is to simulate network congestion with the following control. We flush out the output stream, sleep, and then continue rendering.
public class FlushAndSleep : Control
protected override void Render(HtmlTextWriter writer)
writer.Write ("Begin Render<br>");
Stick the control into the following page:
<%@ Register TagPrefix="otc" Assembly="App_Code" Namespace="OTC" %>
<form id="form1" runat="server">
<asp:textbox runat="server" id="TextBox1" />
<asp:button runat="server" id="Button1" text="Submit" />
<otc:FlushAndSleep runat="server" ID="FlushAndSleep" />
Run the page and click the button as soon as it appears in the browser. Voila! Instant "invalid callback or postback argument" exception! If you ever see the exception occur sporadically, this might be the reason.