2

I hav a view model

public class MyViewModel
{
    [RegularExpression(@"^([0-9a-zA-Z]+([-._])?)?[0-9a-zA-Z]+(\2?[0-9a-zA-Z]+)*$")]
    public string UserName { get; set; }
}

And my action inside my controller:

[HttpPost]
public ActionResult Edit(MyViewModel model, string button)

And my unit test that tests the model data annotaion validation similar as explained here

If I test this regex with a name with space (say "Robert Johnson"), it doesn't match. If I use the same input in my unit tests, an error is raised from and the tests pass (expected behavior)

But when I call the action, the action accepts the data normally. Event if I call ModelState.IsValid, I get a "false" returned.

As far as I know, my action should not be called if the model validation fails. How can I ensure this behavior?

Community
  • 1
  • 1
JSBach
  • 4,679
  • 8
  • 51
  • 98
  • 1
    It would only not be called if client-side validation was active, and the data was invalid. Otherwise, the data would be POSTed as normal for your action to validate server-side. – John H Nov 21 '13 at 21:37
  • I will look into that tomorrow and let you know if this worked. Tks! – JSBach Nov 21 '13 at 21:40
  • 5
    As a side note, your action will always be called at some point, regardless of whether the data is valid or not. Remember, client-side validation is there essentially for usability reasons. Validation should _always_ occur on the server. Client-side validation is optional; server-side isn't. – John H Nov 21 '13 at 21:43
  • Yes, that is true. Thanks for this side note, I will remember that when making the required changes – JSBach Nov 22 '13 at 14:09

1 Answers1

4

Data annotations can be used to validate models on both the client and the server.

On the server-side the DefaultModelBinder will automatically validate the models that are POSTed to your action methods but it won't prevent invalid models from being POSTed. It will simply add the error to the ModelState and set the ModelState.IsValid property to false (as you have discovered). That means you need to check the ModelState.IsValid property and redisplay the form with the model if it isn't valid:

[HttpPost]
public ActionResult Edit(MyViewModel model, string button)
{
    if (!ModelState.IsValid)
    {
        // The model isn't valid.  
        // Redisplay the form with the invalid model.
        return View(model);
    }


    // If we got here it means the model is valid.
}

Redisplaying the form with the invalid model will allow any @Html.ValidationSummary() or @Html.ValidationMessageFor(m => m.UserName) helper methods to render their validation error messages to the page.

As far as I know, my action should not be called if the model validation fails.

This is only true if client-side validation is enabled. You can do this by adding the following appSettings to your Web.config file:

<appSettings>
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>

... and adding references to the jquery.validate.js and jquery.validate.unobtrusive.js scripts to your view. This will allow JavaScript to validate the model before it is sent to the server and the validation messages will show without a page refresh (much better for the user and your server!). As @John H pointed out in the question comments, client-side validation is no substitute for server-side validation. So be sure to leave your server-side validation checks in place.

Kevin Aenmey
  • 13,259
  • 5
  • 46
  • 45
  • Thanks to you and @John H, I've learned a lot with you two guys. I am still missing something to prevent the postback to my action, I will spend some more time re-reading you answer and researching about it. If I fail, I might come back to this question :) – JSBach Nov 22 '13 at 14:31
  • FYI, I wasn't referencing Jquery. Now it works perfectly. Thanks guys :D – JSBach Nov 22 '13 at 14:48