tutorial net mvc espaƱol ejemplo curso create asp c# asp.net-mvc

c# - net - El elemento ViewData que tiene la clave ''XXX'' es del tipo ''System.Int32'' pero debe ser del tipo ''IEnumerable<SelectListItem>''



mvc c# (5)

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 una Category

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() , y si paso la SelectList usando un ViewBag o ViewBag .


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

No está generando una entrada para cada propiedad de cada SelectListItem en CategoryList (y tampoco debería hacerlo), por lo que no se publican valores para SelectList en el método del controlador y, por lo tanto, el valor de model.CategoryList en 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() finalmente 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 selectList (el segundo parámetro de @Html.DropDownListFor() ) es null

// 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, @Html.DropDownListFor() )

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

Como la propiedad IdCategoría es typeof int , no se puede convertir en IEnumerable<SelectListItem> y se IEnumerable<SelectListItem> la excepción (que se define en el archivo MvcResources.resx 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>


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, ya sea a través de la bolsa de visualización o mediante los ayudantes de valor oculto.


OK, la respuesta enlatada del póster explicaba perfectamente por qué ocurrió el error, pero no cómo hacer que funcione. No estoy seguro de que sea realmente una respuesta, pero me señaló en la dirección correcta.

Me encontré con el mismo problema y encontré una forma ingeniosa de resolverlo. Trataré de capturar eso aquí. Descargo de responsabilidad: trabajo en páginas web una vez al año más o menos y realmente no sé lo que hago la mayor parte del tiempo. Esta respuesta no debe considerarse de ninguna manera una respuesta "experta", pero hace el trabajo con poco trabajo ...

Dado que tengo algún objeto de datos (muy probablemente un Objeto de transferencia de datos) que quiero usar una lista desplegable para proporcionar valores válidos para un campo, así:

public class MyDataObject { public int id; public string StrValue; }

Entonces el ViewModel se ve así:

public class MyDataObjectVM { public int id; public string StrValue; public List<SectListItem> strValues; }

El verdadero problema aquí, como @Stephen describió anteriormente de manera tan elocuente, es que la lista de selección no se completa en el método POST en el controlador. Entonces sus métodos de controlador se verían así:

// GET public ActionResult Create() { var dataObjectVM = GetNewMyDataObjectVM(); return View(dataObjectVM); // I use T4MVC, don''t you? } private MyDataObjectVM GetNewMyDataObjectVM(MyDataObjectVM model = null) { return new MyDataObjectVM { int id = model?.Id ?? 0, string StrValue = model?.StrValue ?? "", var strValues = new List<SelectListItem> { new SelectListItem {Text = "Select", Value = ""}, new SelectListITem {Text = "Item1", Value = "Item1"}, new SelectListItem {Text = "Item2", Value = "Item2"} }; }; } // POST public ActionResult Create(FormCollection formValues) { var dataObject = new MyDataObject(); try { UpdateModel(dataObject, formValues); AddObjectToObjectStore(dataObject); return RedirectToAction(Actions.Index); } catch (Exception ex) { // fill in the drop-down list for the view model var dataObjectVM = GetNewMyDataObjectVM(); ModelState.AddModelError("", ex.Message); return View(dataObjectVM); ) }

Ahí tienes. Este NO es un código de trabajo, copié / pegué y edité para simplificarlo, pero entiendes la idea. Si los miembros de datos tanto en el modelo de datos original como en el modelo de vista derivado tienen el mismo nombre, UpdateModel () hace un trabajo increíble al completar los datos correctos para usted a partir de los valores de FormCollection.

Estoy publicando esto aquí para poder encontrar la respuesta cuando inevitablemente vuelva a encontrarme con este problema, espero que también ayude a alguien más.


Tuve el mismo problema, recibí un ModelState no válido cuando intenté publicar el formulario. Para mí, esto fue causado al establecer CategoryId en int, cuando lo cambié a string el ModelState era válido y el método Create funcionó como se esperaba.


según la answer stephens (user3559349), esto puede ser útil:

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

o en ProjectVM:

public class ProjectVM { public ProjectVM() { CategoryList = new List<SelectListItem>(); } ... }