一尘不染

键为“ XXX”的ViewData项的类型为“ System.Int32”,但必须类型为“ IEnumerable”'

c#

我有以下视图模型

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

和以下控制器方法来创建新项目并分配一个 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项的类型为“
System.Int32”,但必须为类型“ IEnumerable ”。

使用@Html.DropDownList()方法会发生相同的错误,如果我使用ViewBag或传递了SelectList,则会发生同样的错误ViewData


阅读 273

收藏
2020-05-19

共1个答案

一尘不染

该错误表示的值为CategoryList
null(因此该DropDownListFor()方法期望第一个参数的类型为IEnumerable<SelectListItem>)。

您不会为SelectListItemin中的每个属性生成一个输入CategoryList(也不应该),因此不会将的值SelectList发布到控制器方法中,因此model.CategoryListPOST方法中的值为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>"));
}

由于property CategoryID是typeof
int,因此无法将其强制转换为IEnumerable<SelectListItem>并且抛出异常(在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>
2020-05-19