El elemento ViewData que tiene la clave 'XXX' es de tipo 'System.Int32' pero debe ser de tipo 'IEnumerable<SelectListItem>'

Resuelto asked hace 9 años • 6 respuestas

Tengo el siguiente modelo de vista.

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

y el siguiente método de controlador para crear un nuevo proyecto y asignar unCategory

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
}

y en la vista

@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" />
}

La vista se muestra correctamente pero al enviar el formulario, aparece el siguiente mensaje de error

InvalidOperationException: el elemento ViewData que tiene la clave 'CategoryID' es del tipo 'System.Int32' pero debe ser del tipo 'IEnumerable<SelectListItem>'.

El mismo error ocurre usando el @Html.DropDownList()método, y si paso SelectList usando a ViewBago ViewData.

 avatar Dec 19 '15 08:12
Aceptado

El error significa que el valor de CategoryList es nulo (y como resultado, el DropDownListFor()método espera que el primer parámetro sea de tipo IEnumerable<SelectListItem>).

No está generando una entrada para cada propiedad de cada SelectListItemuno CategoryList(y tampoco debería hacerlo), por lo que no se SelectListpublican valores para el método del controlador y, por lo tanto, el valor de model.CategoryListen el método POST es null. Si devuelve la vista, primero debe reasignar el valor de CategoryList, tal como lo hizo en el método 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
}

Para explicar el funcionamiento interno (el código fuente se puede ver aquí )

Cada sobrecarga de DropDownList()y DropDownListFor()eventualmente llama al siguiente método

private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMetadata metadata,
  string optionLabel, string name, IEnumerable<SelectListItem> selectList, bool allowMultiple,
  IDictionary<string, object> htmlAttributes)

que comprueba si el selectList(el segundo parámetro de @Html.DropDownListFor()) esnull

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

que a su vez llama

private static IEnumerable<SelectListItem> GetSelectData(this HtmlHelper htmlHelper, string name)

que evalúa el primer parámetro de @Html.DropDownListFor()(en este caso 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>"));
}

Debido a que la propiedad CategoryIDes typeof int, no se puede convertir IEnumerable<SelectListItem>y se genera la excepción (que se define en el MvcResources.resxarchivo como)

<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>
 avatar Dec 19 '2015 01:12

Según la respuesta de Stephens (user3559349) , esto puede ser útil:

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

o en ProyectoVM:

public class ProjectVM
{
    public ProjectVM()
    {
        CategoryList = new List<SelectListItem>();
    }
    ...
}
Omid.Hanjani avatar Nov 25 '2018 12:11 Omid.Hanjani

Lo más probable es que haya causado algún tipo de error al redirigir a su página y no haya inicializado las listas desplegables de su modelo nuevamente.

Asegúrese de inicializar sus menús desplegables en el constructor del modelo o cada vez antes de enviar dicho modelo a la página.

De lo contrario, deberá mantener el estado de las listas desplegables a través de la bolsa de visualización o mediante los ayudantes de valores ocultos.

Gavin Rotty avatar May 20 '2019 18:05 Gavin Rotty