I have the following view model
public class ProjectVM
{
....
[Display(Name = "Category")]
[Required(ErrorMessage = "Please select a category")]
public int CategoryID { get; set; }
public IEnumerable<SelectListItem> CategoryList { get; set; }
....
}
and the following controller method to create a new Project and assign a Category
public ActionResult Create()
{
ProjectVM model = new ProjectVM
{
CategoryList = new SelectList(db.Categories, "ID", "Name")
}
return View(model);
}
public ActionResult Create(ProjectVM model)
{
if (!ModelState.IsValid)
{
return View(model);
}
// Save and redirect
}
and in the view
@model ProjectVM
....
@using (Html.BeginForm())
{
....
@Html.LabelFor(m => m.CategoryID)
@Html.DropDownListFor(m => m.CategoryID, Model.CategoryList, "-Please select-")
@Html.ValidationMessageFor(m => m.CategoryID)
....
<input type="submit" value="Create" />
}
The view displays correctly but when submitting the form, I get the following error message
InvalidOperationException: The ViewData item that has the key 'CategoryID' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'.
The same error occurs using the @Html.DropDownList()
method, and if I pass the SelectList using a ViewBag
or ViewData
.
I had the same problem, I was getting an invalid ModelState when I tried to post the form. For me, this was caused by setting CategoryId to int, when I changed it to string the ModelState was valid and the Create method worked as expected.
The error means that the value of
CategoryList
is null (and as a result theDropDownListFor()
method expects that the first parameter is of typeIEnumerable<SelectListItem>
).You are not generating an input for each property of each
SelectListItem
inCategoryList
(and nor should you) so no values for theSelectList
are posted to the controller method, and therefore the value ofmodel.CategoryList
in the POST method isnull
. If you return the view, you must first reassign the value ofCategoryList
, just as you did in the GET method.To explain the inner workings (the source code can be seen here)
Each overload of
DropDownList()
andDropDownListFor()
eventually calls the following methodwhich checks if the
selectList
(the second parameter of@Html.DropDownListFor()
) isnull
which in turn calls
which evaluates the the first parameter of
@Html.DropDownListFor()
(in this caseCategoryID
)Because property
CategoryID
is typeofint
, it cannot be cast toIEnumerable<SelectListItem>
and the exception is thrown (which is defined in theMvcResources.resx
file as)according to stephen answer, this can be useful:
or in ProjectVM: