ASP.NET MVC default binder: too long ints, empty validation error message
Asked Answered
V

2

8

I've got the following model class (stripped for simplicity):

public class Info
{
    public int IntData { get; set; }
}

Here's my Razor form that uses this model:

@model Info
@Html.ValidationSummary()
@using (Html.BeginForm())
{
    @Html.TextBoxFor(x => x.IntData)
    <input type="submit" />
}

Now if I enter a non-numeric data into the textbox, I receive a correct validation message, i.e.: "Value 'qqqqq' is not valid for field 'IntData'".

But if I enter a very long sequence of digits (like 345234775637544), I receive an EMPTY validation summary.

In my controller code, I see that ModelState.IsValid is false as expected, and ModelState["IntData"].Errors[0] is as follows:

{System.Web.Mvc.ModelError}
ErrorMessage: ""
Exception: {"The parameter conversion from type 'System.String' to type 'System.Int32' failed. See the inner exception for more information."}

(exception itself) [System.InvalidOperationException]: {"The parameter conversion from type 'System.String' to type 'System.Int32' failed. See the inner exception for more information."}
InnerException: {"345234775637544 is not a valid value for Int32."}

As you can see, the validation works normally, but doesn't yield an error message to the user.

Can I tweak the default model binder's behavior so that it shows a proper error message in this case? Or will I have to write a custom binder?

Virgievirgil answered 6/6, 2011 at 12:40 Comment(0)
C
8

One way would be to write a custom model binder:

public class IntModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (value != null)
        {
            int temp;
            if (!int.TryParse(value.AttemptedValue, out temp))
            {
                bindingContext.ModelState.AddModelError(bindingContext.ModelName, string.Format("The value '{0}' is not valid for {1}.", value.AttemptedValue, bindingContext.ModelName));
                bindingContext.ModelState.SetModelValue(bindingContext.ModelName, value);
            }
            return temp;
        }
        return base.BindModel(controllerContext, bindingContext);
    }
}

which could be registered in Application_Start:

ModelBinders.Binders.Add(typeof(int), new IntModelBinder());
Cabala answered 9/6, 2011 at 8:58 Comment(2)
Thank you, I'll opt for this solution if I won't be able to tweak the default binder.Virgievirgil
I suggest changing bindingContext.ModelName to bindingContext.ModelMetadata.DisplayName if you want localized fieldname over attribute [Display(Name=...)].Raybin
G
1

How about setting MaxLength on the input field to 10 or so? I would do that in combination with setting a range on IntData. Unless of course you want allow a user to enter 345234775637544. In that case you're better off with a string.

Ghat answered 10/6, 2011 at 2:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.