具有键“XXX”的ViewData项的types为“System.Int32”,但必须为“IEnumerable <SelectListItem>”types

我有以下视图模型

public class ProjectVM { .... [Display(Name = "Category")] [Required(ErrorMessage = "Please select a category")] public int CategoryID { get; set; } public IEnumerable<SelectListItem> CategoryList { get; set; } .... } 

和下面的控制器方法来创build一个新的项目并分配一个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 } 

并在视图中

 @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" /> } 

该视图正确显示但提交表单时,我收到以下错误信息

InvalidOperationException:具有“CategoryID”键的ViewData项的types为“System.Int32”,但必须是“IEnumerable <SelectListItem>”types。

使用@Html.DropDownList()方法发生同样的错误,如果我使用ViewBagViewData传递SelectList。

该错误意味着CategoryList值为null(因此DropDownListFor()方法期望第一个参数的types为IEnumerable<SelectListItem> )。

您不会为CategoryList的每个SelectListItem每个属性生成input(也不应该),因此SelectList值不会发布到控制器方法,因此POST方法中的model.CategoryList的值为null 。 如果返回视图,则必须先重新分配CategoryList的值,就像在GET方法中一样。

 public ActionResult Create(ProjectVM model) { if (!ModelState.IsValid) { model.CategoryList = new SelectList(db.Categories, "ID", "Name"); // add this return View(model); } // Save and redirect } 

为了解释内部工作原理(可以在这里看到源代码)

DropDownList()DropDownListFor()每个重载最终调用以下方法

 private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMetadata metadata, string optionLabel, string name, IEnumerable<SelectListItem> selectList, bool allowMultiple, IDictionary<string, object> htmlAttributes) 

它检查selectList@Html.DropDownListFor() )的第二个参数是否为null

 // If we got a null selectList, try to use ViewData to get the list of items. if (selectList == null) { selectList = htmlHelper.GetSelectData(name); usedViewData = true; } 

而这又称为

 private static IEnumerable<SelectListItem> GetSelectData(this HtmlHelper htmlHelper, string name) 

它会评估@Html.DropDownListFor()的第一个参数(在这种情况下是CategoryID

 .... o = htmlHelper.ViewData.Eval(name); .... IEnumerable<SelectListItem> selectList = o as IEnumerable<SelectListItem>; if (selectList == null) { throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, MvcResources.HtmlHelper_WrongSelectDataType, name, o.GetType().FullName, "IEnumerable<SelectListItem>")); } 

由于属性CategoryID是typeof int ,因此无法将其转换为IEnumerable<SelectListItem>并抛出exception(在MvcResources.resx文件中将其定义为)

 <data name="HtmlHelper_WrongSelectDataType" xml:space="preserve"> <value>The ViewData item that has the key '{0}' is of type '{1}' but must be of type '{2}'.</value> </data>