O item ViewData que possui a chave 'MY KEY' é do tipo 'System.String', mas deve ser do tipo 'IEnumerable <SelectListItem>'

142

Estou tentando preencher uma lista suspensa de um banco de dados mapeado com Linq-2-SQL, usando o ASP.NET MVC 2, e continuo recebendo esse erro.

Estou tão confuso porque estou declarando uma variável do tipo IEnumerable<SelectListItem>na segunda linha, mas o erro me faz pensar que esse não é o caso. Eu sinto que isso deve ser muito simples, mas estou lutando. Qualquer ajuda é apreciada.

Aqui estão os bits interessantes do meu controlador:

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();
}

E aqui estão os bits interessantes da minha opinião:

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

Aqui está a ação POST ao enviar o formulário

// 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);
    }
}

Obrigado.

JBibbs
fonte
1
A lista suspensa aparece bem na exibição. Ele preenche o banco de dados como deveria, mas é quando eu publico o formulário que recebo esses erros.
JBibbs
6
Resumo da resposta aceita: certifique-se de preencher a lista nas ações get e post do seu controlador. É fácil esquecer de fazer isso e acabar perdendo tempo procurando um bug mais complicado.
Adam Tolley

Respostas:

208

Eu tive o mesmo problema, e finalmente consegui a resposta ...

O problema é que, na ação POST, após o envio do formulário, o ModelState não é válido ou está detectando um erro na tentativa / captura, portanto a Visualização é retornada. Mas desta vez a View não está ViewData["basetype"]configurada corretamente.

Você precisa preenchê-lo novamente, provavelmente com o mesmo código usado antes, então repita isso:

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

antes do return View(meal)no [HttpPost]método.

exatamente isso resolverá seu problema:

[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);
    }
}

Sei que essa pergunta é muito antiga, mas vim aqui hoje com o mesmo problema, para que outros possam vir aqui mais tarde ...

Peto
fonte
8
+1 para "preenchê-lo novamente" ... Eu tenho um sistema bastante robusto para compor meus modelos de exibição, mas esqueci completamente de chamá-lo. Assim, a propriedade não foi preenchida e eu recebi essa mensagem (bastante ambígua), não importa o que eu tentasse.
Tim Medora
8
se você receber isso ANTES de um post, é porque não há nada no SelectList, apenas o encontrou.
Martin Martin
1
+1 Porque eu estava definindo meu ViewBag no método Index quando estava realmente chamando um Html.Action para outro método de ação !!
SwampyFox
Obrigado. Seria bom se fosse preservado, mas suponho que não seria o "caminho" do MVC.
Casey
se o modelo está ficando inválido, então eu venho os dados enviados pelo usuário serão salvos no banco de dados? Eu também estou enfrentando o mesmo problema. eu sou um novato. corrija-me se eu estiver errada.
Koushik Saha #
87

Você receberá esse erro se o SelectList for nulo.

Ben
fonte
3
Sim, esse é um erro / supervisão comum quando você configura o SelectList em um GET e, em seguida, envia para uma ação POST (obviamente) que possui um, ModelState.IsValid==falseassim você retorna o modelo, return View(model) mas não repovoa sua origem do SelectList antes de retornar do POST. Como não há WebForms do ViewState ala, não há fonte para o @Html.DropDownauxiliar reconstruir a seleção. Você precisa preencher essa lista de fontes Toda vez que retornar a exibição para o cliente, não apenas no GET.
Rism
Sim, este foi o meu problema. Esqueceu de preencher o selectList na chamada de recebimento. Erro muito enganador. Ótimo post.
Matt
1

Para futuros leitores, se você estiver usando navalha, tente alterar o tipo de item da lista de seleção de List para IEnumerable.

De

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

Para

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

Tente adicionar uma sequência para o nome da sua lista suspensa como o primeiro parâmetro e retire o item dos seus dados de exibição:

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

Aqui também está um método de extensão que você pode usar para que a lista suspensa seja configurada em um estilo semelhante ao de seus outros controles:

        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);
    }

Por exemplo

<%= Html.DropDownList(x => x.BaseType, (IEnumerable<SelectListItem>)ViewData["basetype"], "")%>
CRice
fonte
0

Você está configurando a coleção como um item no dicionário ViewData e tentando recuperá-la como propriedade no modelo. Uma correção simples seria referenciá-lo da mesma maneira que você o define:

    <%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>

Como alternativa, o código abaixo usa uma exibição fortemente tipada:

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 });
    }

Em seguida, na sua exibição fortemente digitada:

    <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>
Igor Zevaka
fonte
Eu tentei usar o código no seu exemplo de "correção simples" e obtive o mesmo erro. Eu deveria ter mencionado que a lista suspensa é preenchida no modo de exibição ok, mas eu recebo esse erro ao enviar o formulário.
JBibbs
Você pode publicar o código da Ação do Controlador que lida com o envio do formulário?
Igor Zevaka 04/08/10
Claro, vou adicioná-lo à postagem original. Obrigado pela vossa ajuda até agora.
JBibbs
0

Se você usar Html.DropDownList() método - o mesmo erro poderá ocorrer, se o item ViewData / Viewbag não estiver definido, como o @Peto respondeu.

Mas pode não estar definido corretamente no caso de um item definido do controlador, mas na visualização principal você usa a chamada parcial do viw com novos valores de ViewDataDictionary.

se você tem @Html.Partial("Partianame", Model,new ViewDataDictionary() { /* ... */ })então a sua visão parcial não vai ver ViewDatae ViewBagdados, remova new ViewDataDictionary()o parâmetro

Evgeny Levin
fonte
0

Para futuros leitores,

Hoje me deparei com o problema e não consegui consertá-lo. Afinal, tornou-se realmente simples. Eu estava trabalhando com uma tabela + vista. Quando atualizei a tabela (adicionei algumas colunas), esqueci de atualizar (descartar e recriar) a exibição, o que causou o problema para mim. Espero que ajude alguém.

Mariano Gianni
fonte
0

Recebi o mesmo erro hoje e minha solução é tornar o modelo "válido".

No meu caso, após o envio do usuário, clicando em "Salvar", obtive o estado do modelo: inválido se o usuário digitar "0", mas o estado do modelo será válido se o usuário digitar "0.0".

Então, eu substituo o método "IsValid" para retornar a verdadeira entrada de usuário "0".

Espero que ajude.

Ray Chung
fonte