views:

928

answers:

3

I'm using an checkbox on an ASP.NET MVC form like so:

<%=Html.CheckBox("AgreeToRules", Model.AgreeToRules)%>

The AgreeToRules property on the model is a boolean value. During testing, this all worked fine. However, now that we've gone live with this app, I'm seeing a relatively small but significant number of errors with the following messaging:

System.Web.HttpUnhandledException: Exception of type 'System.Web.HttpUnhandledException' was thrown. ---> System.InvalidOperationException: The parameter conversion from type 'System.String' to type 'System.Boolean' failed. See the inner exception for more information. ---> System.FormatException: Y is not a valid value for Boolean. ---> System.FormatException: String was not recognized as a valid Boolean.

This appears to happen when the view engine tries to render the form after a post, and the value of the checkbox that is returned from the ValueProvider looks like:

Y,false

OR

N,false

The html that is rendered in the original form looks like:

<input id="AgreeToRules" name="AgreeToRules" type="checkbox" value="true" />
<input name="AgreeToRules" type="hidden" value="false" />

During testing, I expected (and showed) the posted value to look like:

true,false

if checked or

false

if not checked. So where is the N and Y coming from?

I added user agent to the list of information returned from the error handler and it appears (so far) that all of the errors are occuring under windows XP with FF 3.0.10, but that's exactly what I have tested with and the problem did not exist during testing.

Any thoughts?

+1  A: 

It's quite possible that your site is being hit by spambots that are submitting this value, and not real users. The more sites I add automated logging and emailing to, the more of these types of "probes" and errors (though not exactly the type you mention, with a "Y" for a checkbox) that I see piling into my inbox. Does your logging also capture the rest of the submitted form contents?

Funka
Yes, and the rest of the data looks solid. That's the problem. I really feel these are valid submissions.
Chris
+1  A: 

Well I found the problem, and thought I'd post it here in case others encounter it. Certain form fillers will detect the fields using the names I've used and try to "fill them" automatically by setting the value to whatever the user has previously used for similarly named fields. Starting late last night, I'm also receiving "UNSUBSCRIBED" and "SUBSCRIBED" as values for a checkbox named "OptIn".

So, the form filler changes the value of the checkbox to something and the user checks the box, resulting in the unexpected value being transmitted to the server.

Any thoughts on dealing with this would be appreciated.

Chris
+1  A: 

Today I came up with a solution for a similar problem that could be perhaps be adapted to fit your particular need. It will "do the job" for what you are asking, but may not be the most reusable solution.

The idea is that you will walk through the posted form fields and fix the "broken" checkbox values. You can create a ValueProviderDictionary a.k.a. IDictionary<string, ValueProviderResult> and then hand that to your UpdateModel method.

public static IDictionary<string, ValueProviderResult> CreateScrubbedValueProvider(NameValueCollection postedForm, string[] checkboxFieldsToScrub)
{
    Dictionary<string, ValueProviderResult> dict = new Dictionary<string, ValueProviderResult>();
    foreach (string key in postedForm.AllKeys) {
     string[] values = postedForm.GetValues(key);
     if (checkboxFieldsToScrub.Contains(key)) {
      // Ensure we have a "true" value instead of "Y" or "YES" or whatever...
      // Note that with a checkbox, only the first value matters, so we will only
      // worry about values[0] and not values[1] (the "unchecked" value, if exists).
      if (values[0] == "Y" || values[0] == "YES") {
       values[0] = "true";
      }
     }
     string value = String.Join(",", values);
     ValueProviderResult vpr = new ValueProviderResult(values, value, null);
     dict.Add(key, vpr);
    }
    return dict;
}

Your controller will need to accept a NameValueCollection (or FormCollection) in its parameters, and you'll need to hand your generated ("scrubbed") value provider dictionary to the UpdateModel method. I haven't tested this exactly, but my version of this is working very similarly for me. Best of luck!

Funka
i was thinking this should be updated to not just detect "Y" or "YES" in your checkbox fields, but to detect *anything* other than the strings "true" or "false"... (Anything not recognized should be set to false.)
Funka