L'élément ViewData qui a la clé 'MY KEY' est de type 'System.String' mais doit être de type 'IEnumerable <SelectListItem>'

142

J'essaie de remplir une liste déroulante à partir d'une base de données mappée avec Linq-2-SQL, en utilisant ASP.NET MVC 2, et continue à obtenir cette erreur.

Je suis tellement confus parce que je déclare une variable de type IEnumerable<SelectListItem>sur la deuxième ligne, mais l'erreur me fait penser que ce n'est pas le cas. Je pense que cela devrait être très simple, mais je me bats. Toute aide est appréciée.

Voici les éléments intéressants de mon contrôleur:

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

Et voici les éléments intéressants de mon point de vue:

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

Voici l'action POST lors de la soumission du formulaire

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

Merci.

JBibbs
la source
1
La liste déroulante apparaît très bien dans la vue. Il remplit la base de données comme il se doit, mais c'est lorsque je poste le formulaire que j'obtiens ces erreurs.
JBibbs
6
Résumé de la réponse acceptée: assurez-vous de renseigner la liste à la fois dans les actions get et post de votre contrôleur. Il est facile d'oublier de faire cela, puis de perdre du temps à chercher un bogue plus compliqué.
Adam Tolley

Réponses:

208

J'ai eu le même problème, et finalement j'ai eu la réponse ...

Le problème est que dans l'action POST, après avoir soumis le formulaire, le ModelState n'est pas valide ou il détecte une erreur dans try / catch, de sorte que la vue est renvoyée. Mais cette fois, la vue n'a pas été ViewData["basetype"]correctement définie.

Vous devez le remplir à nouveau, probablement avec le même code utilisé auparavant, alors répétez ceci:

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

avant le return View(meal)dans la [HttpPost]méthode.

exactement cela résoudra votre problème:

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

Je sais que cette question est très ancienne, mais je suis venu ici aujourd'hui avec le même problème, donc d'autres pourraient venir ici plus tard ...

Peto
la source
8
+1 pour "peupler à nouveau" ... J'ai mis en place un système assez robuste pour composer mes modèles de vue, mais j'avais complètement oublié de l'appeler. Ainsi, la propriété n'était pas peuplée et j'ai reçu ce message (plutôt ambigu), peu importe ce que j'ai essayé.
Tim Medora
8
si vous obtenez ceci AVANT un post, c'est parce qu'il n'y a rien dans la SelectList, je viens de trouver celui-là.
Martin
1
+1 Parce que je définissais mon ViewBag dans la méthode Index lorsque j'appelais vraiment un Html.Action à une autre méthode d'action !!
SwampyFox
Merci. Ce serait bien s'il était simplement préservé, mais je suppose que ce ne serait pas la «voie» MVC.
Casey
si le modèle est invalidé alors je viens que les données soumises par l'utilisateur seront enregistrées dans la base de données? je suis également confronté au même problème. je suis un débutant. Corrigez-moi si je me trompe.
Koushik Saha
87

Vous recevrez cette erreur si la SelectList est nulle.

Ben
la source
3
Oui, c'est une erreur / oubli courante lorsque vous configurez la SelectList sur un GET, puis publiez une action POST (évidemment) qui a un ModelState.IsValid==falsedonc vous renvoyez le modèle return View(model) mais ne remplissez pas votre source SelectList avant de revenir du POST. Comme il n'y a pas de ViewState ala WebForms, il n'y a pas de source avec laquelle l' @Html.DropDownassistant peut reconstruire la sélection. Vous devez remplir cette liste source CHAQUE fois que vous renvoyez la vue au client et pas seulement sur le GET.
rism
oui c'était mon problème. Oublié de remplir la selectList lors de l'appel get. Erreur très trompeuse. Très bonne publication.
Matt
1

Pour les futurs lecteurs, si vous utilisez Razor, essayez de changer le type d'élément de la liste de sélection de List à IEnumerable.

De

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

À

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

Essayez d'ajouter une chaîne pour le nom de votre liste déroulante en tant que premier paramètre et retirez l'élément de vos données d'affichage:

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

Voici également une méthode d'extension que vous pouvez utiliser pour que la liste déroulante soit configurée dans un style similaire à la façon dont vous avez effectué vos autres contrôles:

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

Par exemple

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

Vous définissez la collection en tant qu'élément dans le dictionnaire ViewData et essayez de la récupérer en tant que propriété sur le modèle. Une solution simple serait de le référencer de la même manière que vous le définissez:

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

Alternativement, le code ci-dessous utilise une vue fortement typée:

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

Ensuite, dans votre vue fortement typée:

    <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
la source
J'ai essayé d'utiliser le code dans votre exemple de "solution simple" et j'ai eu la même erreur. J'aurais dû mentionner que la liste déroulante apparaît dans la vue ok, mais j'obtiens cette erreur lorsque j'envoie le formulaire.
JBibbs
Pouvez-vous publier le code de l'action du contrôleur qui gère la soumission du formulaire?
Igor Zevaka
Bien sûr, je l'ajouterai au message d'origine. Merci pour votre aide jusqu'à maintenant.
JBibbs
0

Si vous utilisez la Html.DropDownList()méthode - la même erreur peut se produire si votre élément ViewData / Viewbag n'est pas défini, comme @Peto a répondu.

Mais il peut ne pas être défini correctement dans le cas d'un élément de jeu de contrôleur, mais dans la vue principale, vous utilisez un appel viw partiel avec de nouvelles valeurs ViewDataDictionary.

si vous avez @Html.Partial("Partianame", Model,new ViewDataDictionary() { /* ... */ })alors votre vue partielle ne verra pas ViewDataet les ViewBagdonnées, supprimez le new ViewDataDictionary()paramètre

Evgeny Levin
la source
0

Aux futurs lecteurs,

Je suis tombé sur le problème aujourd'hui et je n'ai pas pu le résoudre. Cela s'est avéré très simple après tout. Je travaillais avec une table + vue. Lorsque j'ai mis à jour le tableau (ajouté quelques colonnes), j'ai oublié de mettre à jour (supprimer et recréer) la vue, ce qui a causé le problème pour moi. J'espère que ça aide quelqu'un.

Mariano Gianni
la source
0

J'ai eu la même erreur aujourd'hui et ma solution est de rendre le modèle "valide".

Dans mon cas, après que l'utilisateur a soumis en cliquant sur "enregistrer", j'ai obtenu l'état du modèle: invalide si l'entrée au clavier de l'utilisateur "0", mais l'état du modèle sera valide si la clé de l'utilisateur est "0.0".

Donc, je remplace la méthode "IsValid" pour renvoyer true même l'entrée au clavier "0".

J'espère que ça aide.

Ray Chung
la source