ASP.NET Event Validation

So I recently came upon this handy part of ASP.NET 2.0 that validates the postback coming onto the server to make sure that the post variables sent (excluding special ASP.NET variables like __VIEWSTATE and __EVENTARGUMENT) back to the server were actually registered by the server controls output to the page.

For example, say you have a drop down list and a button on a page like this:

Page Layout

Using Fiddler, we can examine the contents of the HTTP request that the browser sends when we click the submit button (most headers are excluded for clarity, and the __VIEWSTATE and __EVENTVALIDATION values have been truncated):

POST /Scratchpad/Default.aspx HTTP/1.1
Host: localhost.:51793

__VIEWSTATE=%2Fw%2B4%3D&ddlFirstName=David&btnSubmit=Submit&__EVENTVALIDATION=%2%3D%3D

Each of our post variables are separated by an ampersand. As you see above, we have four post variables: __VIEWSTATE, ddlFirstName (our drop down list), btnSubmit (our button), and _EVENTVALIDATION. With Fiddler we can also tamper with the request, so let’s actually send a request that chooses a first name of “Josh” instead of any of the other options.

POST /Scratchpad/Default.aspx HTTP/1.1
Host: localhost:51793
Content-Type: application/x-www-form-urlencoded
Content-Length: 186

__VIEWSTATE=%2Fs%3D&ddlFirstName=Josh&btnSubmit=Submit&__EVENTVALIDATION=%E%3D
Uh oh! ASP.NET then sends us back this error:
Event Validation Error

So why does this happen? When a postback occurs, ASP.NET must populate the values of the server controls with their respective values. (i.e. Text boxes must be populated with the text input by a user, and drop downs must have their selected values set appropriately, and so on.) In Page.ProcessPostData, the page tries to find a child control with the specified ID from the postData (matching ddlFirstName to its actual DropDownList control). If it can find that control, it tries to find that control’s PostBackDataHandler, which is an IPostBackDataHandler instance which can handle the loading of that post data. In most cases this is the control itself, but in others it can be a ControlAdapter hooked up to that Control.

It calls the LoadPostData method on that PostBackDataHandler instance. In the case of the DropDownList, its LoadPostData validates that the value posted for it to select (in this case, “Josh”) is valid. This combination is deemed valid if, before the page was rendered, the DropDownList registered that value by using the ClientScriptManager.RegisterForEventValidation method. Event validation XORs the hashes of the unique ID of the control (”ddlFirstName”) and the input value (”Josh”). If that value is present in a name table, then validation passes, because obviously the control registered that combination of values { {”ddlFirstName”, “David”}, {”ddlFirstName”, “Fred”}, {”ddlFirstName”, “George”} }. But since there is no {”ddlFirstName”, “Josh”} validation fails.

Most of the time this is the desired behavior. You don’t want people posting invalid data to your page. However, there are a few times where this is not what you want. Take, for example, when you are adding dynamic values to the DropDownList control based on client-side code, such as an AJAX call. This error will come up if the user chooses a value that was populated by the client and not by the server. There are a couple of alternatives you have:

  1. Add <%@ Page EnableEventValidation=”false” %> to the page directive.
  2. Add to the web.config.
  3. Use the ClientScriptManager.RegisterForEventValidation method to let ASP.NET know about all possible postback values and/or controls.
  4. Make something that magically disables event validation on a control-by-control basis.

#1 and #2 have the disadvantage of disabling event validation for everything on the page, even though you may have a problem with just a specific control.

#3 is a good alternative if all the values being populated on the client-side are known. For example, if a script were to add “Josh” and “Simon” to our first name drop down, we would have to make sure that the validation table has those values populated. To do that, we can make a custom control derived from DropDownList and override its Render method:

[ToolboxData("<{0}:CustomDropDownList runat=\"server\">")]

[SupportsEventValidation]

public class CustomDropDownList : System.Web.UI.WebControls.DropDownList

{

    protected override void Render(HtmlTextWriter writer)

    {

        base.Render(writer);

 

        string ddlID = this.UniqueID;

        // ClientScript is the Page’s reference to the ClientScriptManager

        this.Page.ClientScript.RegisterForEventValidation(ddlID, “Josh”);

        this.Page.ClientScript.RegisterForEventValidation(ddlID, “Simon”);

    }

}

So we call RegisterForEventValidation while passing in the UniqueID of the control itself and a value that should be anticipated–”Josh” or “Simon,” in this case.

Onto #4…well, I don’t think there is a cure-all for this. But the problem arises where you don’t know what will be populated on the client-side. So far I’ve seen around most blogs that the only way to really handle this situation is to do manual validation of the input and turn event validation off for the page or the entire site. I have a tentative solution that addresses turning off validation for a single control, but it will take another blog post for me to address it since it also fits in with the dynamic data entry control framework I’ve been working on. I know I haven’t talked about that either, but it’s on the way!

Hope this helps some people…

One Response to “ASP.NET Event Validation”

  1. Andy Baker Says:

    Perfect, thank you for publishing this article! Its rare to find something so concise and with a simple, but real world example.

Leave a Reply