键为“ XXX”的 ViewData 项的类型为“ System. Int32”,但必须为“ IEnumable < SelectListItem >”类型

我有以下视图模型

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

以及下面的控制器方法,以创建一个新的 Project 并分配一个 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: 键值为“ Category oryID”的 ViewData 项属于“ System. Int32”类型,但必须属于“ IEnumable < SelectListItem >”类型。

如果我使用 ViewBagViewData传递 SelectList,也会发生同样的错误。

58757 次浏览

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

您不会为 CategoryList中每个 SelectListItem的每个属性生成输入(您也不应该这样做) ,因此 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>"));
}

因为属性 CategoryIDint的类型,所以不能将其强制转换为 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>

我遇到了同样的问题,当我尝试发布表单时,我得到了一个无效的 ModelState。对于我来说,这是由于将 Category oryId 设置为 int,当我将其更改为 string 时,ModelState 是有效的,Create 方法按预期工作。

根据 stephens (user3559349) 回答,这可能是有用的:

@Html.DropDownListFor(m => m.CategoryID, Model.CategoryList ?? new List<SelectListItem>(), "-Please select-")

或在 ProjectVM 中:

public class ProjectVM
{
public ProjectVM()
{
CategoryList = new List<SelectListItem>();
}
...
}

最有可能导致某种错误重定向到您的页面,并且您没有再次初始化您的模型的下拉列表。

确保您在模型的构造函数中或者每次将模型发送到页面之前都初始化了下拉列表。

否则,您将需要通过视图包或通过隐藏值助手来维护下拉列表的状态。

好吧,海报的录音回答干净利落地解释了 为什么错误发生的原因,但没有说明如何让它工作。我不确定这是不是一个真正的答案,但它确实为我指明了正确的方向。

我遇到了同样的问题,并找到了一个巧妙的方法来解决它。我会在这里记录下来。免责声明-我工作在网页一年左右,真的不知道我在做什么的大部分时间。这个答案不应该被认为是一个“专家”的答案,但它的工作与很少的工作..。

假设我有一些数据对象(很可能是数据传输对象) ,我想使用下拉列表为字段提供有效值,如下所示:

public class MyDataObject
{
public int id;
public string StrValue;
}

然后 ViewModel 看起来像这样:

public class MyDataObjectVM
{
public int id;


public string StrValue;
public List<SectListItem> strValues;
}

这里真正的问题,正如上面@Stephen 雄辩地描述的那样,是没有在控制器中的 POST 方法上填充 select 列表。所以你的控制器方法应该是这样的:

// GET
public ActionResult Create()
{
var dataObjectVM = GetNewMyDataObjectVM();
return View(dataObjectVM); // I use T4MVC, don't you?
}


private MyDataObjectVM GetNewMyDataObjectVM(MyDataObjectVM model = null)
{
return new MyDataObjectVM
{
int id = model?.Id ?? 0,
string StrValue = model?.StrValue ?? "",
var strValues = new List<SelectListItem>
{
new SelectListItem {Text = "Select", Value = ""},
new SelectListITem {Text = "Item1", Value = "Item1"},
new SelectListItem {Text = "Item2", Value = "Item2"}
};
};
}


// POST
public ActionResult Create(FormCollection formValues)
{
var dataObject = new MyDataObject();


try
{
UpdateModel(dataObject, formValues);
AddObjectToObjectStore(dataObject);


return RedirectToAction(Actions.Index);
}
catch (Exception ex)
{
// fill in the drop-down list for the view model
var dataObjectVM = GetNewMyDataObjectVM();
ModelState.AddModelError("", ex.Message);


return View(dataObjectVM);
)
}

就是这样。这不是工作代码,我复制/粘贴和编辑使它简单,但你得到的想法。如果原始数据模型和派生视图模型中的数据成员具有相同的名称,UpdateModel ()就可以很好地从 FormCollection 值中为您填充正确的数据。

我把这个贴在这里,这样当我不可避免地再次遇到这个问题时,我可以找到答案——希望它也能帮助其他人。

在我的例子中,列表中的第一个 ID 为零,一旦我将 ID 从1开始更改,它就工作了。