tags:

views:

519

answers:

4

Hi,

Let's say you have simple object like this :

public class MyObject {
    public int Test { get; set; }
}

And you count on the default model binder to make sure the user does not leave the "Test" field empty when posting a form like below :

<form method="post" action="/test">
    <p>
        <%=Html.TextBox("Test") %>
        <%=Html.ValidationMessage("Test") %>
    </p>
    <input id="Submit1" type="submit" value="submit" />
 </form>

And this action :

[AcceptVerbs(HttpVerbs.Post)]
 public ActionResult Test(MyObject o) {
     return View();
 }

This all works as expected when the form data contains a key for "Test" (like "Test=val" or "Test=")

But if the key is not in the form data, then the validation doesn't occur. So in case of an empty post request or a request with a data like AnotherField=foo the property on the model object defaults to the type's default value (in this case 0). And ModelState.IsValid returns true.

This is, IMO, not the behaviour one would expect.
So what do you suggest to change this behaviour?

Edit : Keep in mind that a malicious user can just tamper the form data easily with FireBug or Tamper Data plugin to pass the default model binder's validations, which could cause some security problems.

+1  A: 

You might consider using xVal to perform the necessary mix of client- and server-side validation. With it, you can add an attribute to your Test property dictating what sort of validation rules (required, regex validation, etc.) apply to it and then, with a little more work, get it to generate JavaScript rules for you as well as pretty easily perform model validation.

You're already aware that you're violating a rule of development - never trust client input. There's really no way around it.

Client-side validation (preventing a round trip to find out that there's an error) is nice-to-have, server-side validation verifying that things truly are in order is a must-have.

48klocs
Actually, the problem I tried to explain is a little different than counting on client side validation. I made the same test with DataAnnotationsModelBinder and got the same result. The problem is the validation does not occur at all if the field is not in the form data.DataAnnotationsModelBinder : http://bradwilson.typepad.com/blog/2009/04/dataannotations-and-aspnet-mvc.htmlI'll take a look at xVal as well. Thanks for the response.
çağdaş
In order to do what you want, you need some way to verify that form values were provided for all the fields you had in the form. There's no super-simple way to do this automatically that I can think of off the top of my head...
Brad Wilson
A: 

i hope its by design because I am about to start relying on this behavior!

in one instance i have two controls which post back the following fields :

ShippingAddress.FirstName
ShippingAddress.LastName
ShippingAddress.Line1
ShippingAddress.Line2

BillingAddress.Email
BillingAddress.FirstName
BillingAddress.LastName
BillingAddress.Line1
BillingAddress.Line2

Note: Billing Address does not have email displayed, even though the underlying model of course still has it

If I have Email as a [Required] data annotation in my model then it will only complain when it is missing from Billing Address.

But I definitely see your point! I'm just relying on it for this one scenario here!

Simon_Weaver
still seems to be the behavior
Simon_Weaver
i love it when i see a SO question and think 'i wish i'd known about that sooner' and then see that i already commented on it 4.5 months earlier!
Simon_Weaver
A: 

After researching all the different ways to get the form values into my controller methods, I discovered that the "safest" was to explicitly define each form field as a parameter to the controller. A side effect is that if a form does NOT have one of the fields, it will throw an exception - which would solve your problem.

Rake36
+1  A: 

It is not validating the fields by design, unfortunately. Please take a look at this Codeplex issue that I've found and commented on.

It is really unfortunate, that MS has decided this is the correct behaviour for their model binder.

I believe the default model binder should validate the whole entity instead of just the posted data.

miha
On a related note: I've had very good results with using Enterprise Library's Validation block -- although that might seem like an overkill for some situtations, it is fairly straightforward to set up. There is no EnterpriseLibraryValidationModelBinder yet, though. :)
miha