input number validating but silently not binding

I just encountered a weird behavior with mvc validation and binding against an int. I have my model as:

class YourModel
{
   ...

   [Range(0, int.MaxValue, ErrorMessage = "Invalid")]
   public int Area { get; set; }

   ...
} 

view:

<div class="form-group">
  <label class="control-label">Area (m<sup>2</sup>)</label>
  <input asp-for="Area" class="form-control" />
  <span asp-validation-for="Area"></span>
</div>

with the above, the input gladly accepts input, say,37.90 but silently put 0 (the int default) on form submission. The poor user wonders why it's not saving and after a couple of trials she starts to get angry with the developer (me, in this case).

What's the logic behind the int validation?

2 answers

  • answered 2018-10-12 00:45 Stephen Muecke

    A value of 37.90 cannot be bound to an int, therefore model binding fails and a ModelState error is added.

    If you are checking that ModelState is valid and returning the view i.e.

    if (!ModelState.IsValid)
    {
        return View(...);
    }
    ... // save and redirect
    

    then the default validation message (The value '37.90' is not valid for Area.) will be displayed.

    Your <input asp-for="Area" .. /> adds the data-val-number attribute which adds the number rule to the $.validator. The number rule is a regex defined as ^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$ which allows decimals. jquery.validate.js does have a digits rule which allows only int values but unfortunately that is not used by mvc, therefore if you want to allow only int values, you will need to add a [RegularExpression] attribute if you want client side validation, and a clearer validation message.

    [RegularExpression(@"\d+", ErrorMessage = "Please enter only whole numbers")]
    [Range(0, int.MaxValue, ErrorMessage = "Invalid")] // consider making the message clearer
    public int Area { get; set; }
    

  • answered 2018-10-12 06:54 Pawan Rai

    Type of input is decimal while type of Area property is int. When ModelBinder tries to convert decimal input '37.90' to int, it fails and assign 0 (default value of int) to Area property.

    As per your Range validation rule any value lies between 0 and max value of int is valid that's why it satisfies validation rule (Since value of Area property is 0) and does not show any error.

    You should change datatype of Area property in your model class to double and according to this adjust your Range Validator.