ViewData элемент с ключом 'ХХХ' имеет тип System.Типа int32' но должны быть типа 'интерфейс IEnumerable '



у меня есть следующие модели представления



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


и следующий метод контроллера, чтобы создать новый проект и присвоить 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
}


и



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


вид отображается правильно, но при отправке формы, я получаю следующее сообщение об ошибке




InvalidOperationException: элемент ViewData с ключом 'CategoryID' имеет тип 'System. Int32', но должен иметь тип 'IEnumerable'.




та же ошибка возникает при использовании @Html.DropDownList() метод, и если я передаю SelectList с помощью ViewBag или ViewData.

485   1  

1 ответ:

ошибка означает, что значение CategoryList равно null (и в результате DropDownListFor() метод ожидает, что первый параметр имеет тип IEnumerable<SelectListItem>).

вы не генерируете входные данные для каждого свойства каждого SelectListItem на CategoryList (и вы не должны) так что никаких значений для SelectList публикуются в методе контроллера, и поэтому значение model.CategoryList в методе POST это null. Если вы возвращаете представление, вы должны сначала переназначить значение CategoryList, так же, как и вы в методе 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
}

чтобы объяснить внутреннюю работу (исходный код может быть посмотреть здесь)

каждая перегрузка DropDownList() и DropDownListFor() в конечном итоге вызывает следующий метод

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

который проверяет, если selectList (второй параметр @Html.DropDownListFor()) составляет 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;
}

, который, в свою очередь, называет

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

, который вычисляет первый параметр @Html.DropDownListFor() (в данном случае 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>"));
}

потому что собственность CategoryID is typeof int, он не может быть приведен к IEnumerable<SelectListItem> и выбрасывается исключение (которое определяется в MvcResources.resx file as)

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

Comments

    Ничего не найдено.