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


142

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

我很困惑,因为我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

6
可接受答案的摘要:确保在控制器的get和post操作中都填充了列表。忘记这样做很容易,然后浪费时间寻找一个更复杂的错误。
亚当·托利

Answers:


208

我遇到了同样的问题,最后我得到了答案...

问题在于,在提交表单后的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;

return View(meal)在该[HttpPost]方法之前。

正是这将解决您的问题:

[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 Medora 2012年

8
如果您在发布之前获得此信息,那是因为SelectList中什么都没有,只是找到了那个。
马丁

1
+1因为当我真正调用Html.Action到另一个Action方法时,我是在Index方法中设置ViewBag的!
SwampyFox

谢谢。如果只是保留它会很好,但是我想那不是MVC的“方法”。
Casey 2014年

如果获取的模型无效,那么我提交的用户提交的数据将保存在数据库中?我也面临着同样的问题。我是新手。如果我错了,请纠正我。
Koushik Saha 2014年

87

如果SelectList为null,则将收到此错误。


3
是的,这是常见的错误/疏忽,当您在GET上设置SelectList然后回发到POST操作(显然)时,该操作具有,ModelState.IsValid==false因此您可以返回模型,return View(model) 但在从POST返回之前不要重新填充SelectList源。由于没有ViewState ala WebForms,因此没有@Html.DropDown帮助者重建选择内容的来源。每次将视图返回给客户端时,不仅要在GET上,您都必须填充该源列表。
rism

是的,这是我的问题。忘记在get调用中填充selectList。极具误导性的错误。很棒的帖子。
马特


1

对于将来的读者,如果您使用的是剃刀,请尝试将selectlist项目的类型从List更改为IEnumerable。

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

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

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

您正在将集合设置为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>

我已经尝试在您的“简单修复”示例中使用该代码,并且遇到了相同的错误。我应该提到下拉列表填充在View ok中,但是在提交表单时出现此错误。
JBibbs

您可以发布处理表单提交的Controller Action的代码吗?
伊戈尔·泽瓦卡

当然,我将其添加到原始帖子中。感谢您一直以来的帮助。
JBibbs

0

如果您使用Html.DropDownList()方法-如果未设置您的ViewData / Viewbag项目,则可能会发生相同的错误,如@Peto回答。

但是在控制器设置项目正确的情况下可能无法正确设置,但是在主视图中,您会使用部分viw调用和新的ViewDataDictionary值。

如果您有,@Html.Partial("Partianame", Model,new ViewDataDictionary() { /* ... */ })那么您的局部视图将不会显示ViewData和显示ViewBag数据,请删除new ViewDataDictionary()参数


0

对于未来的读者,

我今天遇到了这个问题,无法解决。毕竟,这真的很简单。我正在使用表+视图。当我更新表(添加一些列)时,我忘记更新(删除并重新创建)视图,这给我带来了问题。希望它能帮助到别人。


0

今天我遇到了同样的错误,我的解决方案是使模型“有效”。

就我而言,在用户单击“保存”提交后,我得到了模型状态:如果用户键入“ 0”,则无效;但是,如果用户键入“ 0.0”,则模型状态将有效。

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

希望能帮助到你。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.