Search code examples
asp.net-mvchtml.dropdownlistforserver-side-validation

ASP.NET MVC fails to bind and validate DropDownListFor if Range is set and Javascript disabled


I have the following property in my model:

    [Required]
    [Range(1, int.MaxValue, ErrorMessage = "Bad number")]
    public virtual int Number { get; set; }

I am filling it in Controller:

List<SelectListItem> items = new List<SelectListItem>();
// numbers is just a list with entities with an integer field Number
items.AddRange(numbers.
                Select(n => new SelectListItem() { Text = n.Number.ToString(), Value = n.Number.ToString() })
                .ToArray());

ViewBag.Numbers = items;

And in my view I have the following:

            @Html.DropDownListFor(m => m.Number, ViewBag.Numbers as IEnumerable<SelectListItem>, "Select a number")
            @Html.ValidationMessageFor(m => m.Number)

It seems to work fine, if Javascript is enabled - when I select the first item (which is empty "Select a number"), Required validator kicks in and does not allow POSTing.

But when I disable Javascript, then I get an exception in my view right on that DropDownListFor method call:

The ViewData item that has the key 'Number' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'. 

When I comment out the [Range], then there is no such exception, but then it seems Required does not work - I can POST the empty "Select a number" option (which has value="") and my model passes validation, but it should not - empty string is not a valid integer! Why does it work fine with Javascript enabled, but fails server-side?


Solution

  • In your POST action don't forget to repopulate the ViewBag.Numbers property, the same way you did in your GET action before returning the View:

    [HttpPost]
    public ActionResult SomeAction(MyViewModel model)
    {
        // some processing ...
    
        // now repopulate the ViewBag if you intend to return the same view
        ViewBag.Numbers = numbers
            .Select(n => new SelectListItem { 
                Text = n.Number.ToString(), 
                Value = n.Number.ToString() 
            })
            .ToList();
    
        return View(model);
    }