具有键“MY KEY”的ViewData项的类型为“System.String”,但必须是“IEnumerable<SelectListItem>”类型。

145

我正在尝试使用Linq-2-SQL映射的数据库,使用ASP.NET MVC 2从中填充下拉列表,并一直收到此错误。

我很困惑,因为在第二行声明了一个IEnumerable<SelectListItem>类型的变量,但错误让我觉得这不是情况。我觉得这应该很简单,但我仍然感到困难。感谢任何帮助。

以下是控制器的有趣部分:

public ActionResult Create()
{
    var db = new DB();
    IEnumerable<SelectListItem> basetypes = db.Basetypes.Select(
        b => new SelectListItem { Value = b.basetype, Text = b.basetype });
    ViewData["basetype"] = basetypes;
    return View();
}

这里是我的视图中有趣的部分:

<div class="editor-label">
   <%: Html.LabelFor(model => model.basetype) %>
</div>
<div class="editor-field">
   <%: Html.DropDownList("basetype") %>
   <%: Html.ValidationMessageFor(model => model.basetype) %>
</div>

这是提交表单时的POST操作

// POST: /Meals/Create
[HttpPost]
public ActionResult Create(Meal meal)
{
    if (ModelState.IsValid)
    {
        try
        {
            // TODO: Add insert logic here
            var db = new DB();
            db.Meals.InsertOnSubmit(meal);
            db.SubmitChanges();
            return RedirectToAction("Index");
        }
        catch
        {
            return View(meal);
        }
    }
    else
    {
        return View(meal);
    }
}
感谢。

1
下拉列表在视图中显示得很好。它从数据库中填充,就像应该的那样,但当我提交表单时,就会出现这些错误。 - JBibbs
8
接受的答案摘要:确保在控制器的get和post操作中都填充列表。很容易忘记这样做,然后浪费时间寻找更复杂的错误。 - Adam Tolley
9个回答

211

我曾经遇到过同样的问题,最终找到了答案...

问题出在提交表单后的POST操作中,ModelState无效或在try/catch中捕获到错误导致返回了View。但是这一次,View没有正确设置ViewData["basetype"]

你需要再次填充它,可能使用之前使用过的相同代码,所以请重复执行此操作:

var db = new DB();
IEnumerable<SelectListItem> basetypes = db.Basetypes.Select(
    b => new SelectListItem { Value = b.basetype, Text = b.basetype });
ViewData["basetype"] = basetypes;

[HttpPost]方法中的return View(meal)之前,加上以下代码将解决您的问题:

[HttpPost]
public ActionResult Create(Meal meal)
{
    if (ModelState.IsValid)
    {
        try
        {
            // TODO: Add insert logic here
            var db = new DB();
            db.Meals.InsertOnSubmit(meal);
            db.SubmitChanges();
            return RedirectToAction("Index");
        }
        catch
        {
            var db = new DB();
            IEnumerable<SelectListItem> basetypes = db.Basetypes.Select(
               b => new SelectListItem { Value = b.basetype, Text = b.basetype });
            ViewData["basetype"] = basetypes;
            return View(meal);
        }
    }
    else
    {
        var db = new DB();
        IEnumerable<SelectListItem> basetypes = db.Basetypes.Select(
            b => new SelectListItem { Value = b.basetype, Text = b.basetype });
        ViewData["basetype"] = basetypes;
        return View(meal);
    }
}

我知道这个问题很旧了,但我今天也遇到了同样的问题,所以其他人以后也可能会来到这里...


8
"+1" 表示同意“再次填充”,我已经建立了一个相当健壮的系统来构建我的视图模型,但我完全忘记调用它。因此,该属性未被填充,无论我尝试什么,都会收到这个(相当含糊)的消息。请帮我翻译为中文。 - Tim M.
8
如果您在发布之前收到此消息,那是因为 SelectList 中没有任何内容,我只是发现了这一点。 - Martin
1
+1 是因为我在 Index 方法中设置了 ViewBag,而实际上我是在调用另一个操作方法的 Html.Action!! - SwampyFox
谢谢。如果只是保留它,那就太好了,但我想这不是MVC的“方式”。 - Casey
@Peto,我有一个包含IList<SelectListItem>的VIEW(页面)模型,在提交后,List<SelectListItem>返回null。因此,即使对于模型,当我想从Post Action返回到同一视图时,我仍需要再次准备List<SelectListItem>。 - Sajjad Ali Khan
显示剩余2条评论

88

如果 SelectList 为空,您将收到此错误。


4
是的,当你在GET请求中设置了SelectList,然后向POST操作(显然)回发一个 ModelState.IsValid==false 的操作时,这是一种常见的错误/疏忽,所以你返回模型 return View(model) 但在从POST返回之前没有重新填充你的SelectList源。因为没有像WebForms那样的ViewState,也就没有 @Html.DropDown助手重建选择列表的源。你必须在每次将视图返回给客户端时都填充该源列表,而不仅仅在GET上。 - rism
是的,这就是我的问题。忘记在获取调用时填充selectList。非常具有误导性的错误。很棒的文章。 - Matt

3

1

对于未来的读者,如果您正在使用razor,请尝试将selectlist项的类型从List更改为IEnumerable。

来自

@Html.DropDownListFor(m => m.id, ViewBag.SomeList as List<SelectListItem>)

@Html.DropDownListFor(m => m.id, ViewBag.SomeList as IEnumerable<SelectListItem>)

0

您正在将集合设置为 ViewData 字典中的一个项,并尝试在模型的属性上检索它。一个简单的解决方法是以与设置相同的方式引用它:

    <%var basetype = ViewData["basetype"] as IEnumerable<SelectListItem>;%>
    <div class="editor-label">
        <%: Html.Label("basetype") %>
    </div>
    <div class="editor-field">
        <%: Html.DropDownList("basetype", basetype) %>
        <%: Html.ValidationMessage("basetype") %>
    </div>

或者,下面的代码使用强类型视图:

public class ViewModel {
   //Model properties
   public IEnumerable<SelectListItem> basetype {get;set;}
}

public ActionResult Create()
    {
        var db = new DB();
        IEnumerable<SelectListItem> basetypes = db.Basetypes.Select(b => new SelectListItem { Value = b.basetype, Text = b.basetype });
        return View(new ViewModel { basetype=basetypes });
    }

接着,在你的强类型视图中:

    <div class="editor-label">
        <%: Html.LabelFor(model => model.basetype) %>
    </div>
    <div class="editor-field">
        <%: Html.DropDownListFor(model=>model.basetype) %>
        <%: Html.ValidationMessageFor(model => model.basetype) %>
    </div>

我尝试使用您的“简单修复”示例中的代码,但是得到了相同的错误。我应该提到下拉列表在视图中填充正常,但是当我提交表单时会出现此错误。 - JBibbs
你能发布处理表单提交的控制器操作的代码吗? - Igor Zevaka
好的,我会将它添加到原始帖子中。感谢你迄今为止的帮助。 - JBibbs

0

尝试将下拉列表的名称字符串作为第一个参数添加,并从您的视图数据中获取项:

 <%= Html.DropDownList("SomeDropdownName", (IEnumerable<SelectListItem>)ViewData["basetype"]) %>

这里还有一个扩展方法,你可以使用它,使得下拉列表以与你的其他控件类似的样式设置:
        public static string DropDownList<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string optionLabel)
        where TModel : class
    {
        string inputName = ExpressionHelper.GetInputName(expression);
        return htmlHelper.DropDownList(inputName, selectList, optionLabel);
    }

例如。
<%= Html.DropDownList(x => x.BaseType, (IEnumerable<SelectListItem>)ViewData["basetype"], "")%>

0

我今天遇到了相同的错误,我的解决方法是将模型“设为有效(valid)”。

在我的情况下,当用户键入“0”时,如果用户提交并点击“保存”,则我会得到模型状态:无效(invalid),但如果用户键入“0.0”,则模型状态将为有效(valid)。

因此,我重写了“IsValid”方法,即使用户键入“0”,也会返回true。

希望能有所帮助。


0

如果您使用Html.DropDownList()方法 - 如果未设置您的ViewData/Viewbag项,则可能会出现相同的错误,就像@Peto所回答的那样。

但是,在控制器正确设置项目的情况下,在主视图中使用新的ViewDataDictionary值进行部分视图调用时,可能不会设置它。

如果您有@Html.Partial("Partianame", Model,new ViewDataDictionary() { /* ... */ }),则您的部分视图将无法看到ViewDataViewBag数据,请删除new ViewDataDictionary()参数。


0

给未来的读者们:

今天我遇到了一个问题,一开始无法解决。但最终发现问题其实非常简单。我在使用表格和视图时,更新了表格(添加了几列),但忘记更新(删除并重新创建)视图,这导致了我的问题。希望能对某些人有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接