1. ホーム
  2. c#

[解決済み] キー 'XXX' を持つ ViewData アイテムは 'System.Int32' 型ですが、'IEnumerable<SelectListItem>' 型である必要があります。

2022-08-09 23:09:46

質問

次のようなビューモデルがあります。

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

と、以下のコントローラメソッドで、新しいProjectを作成し、そのProjectに 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です。キー 'CategoryID' を持つ ViewData アイテムは 'System.Int32' 型ですが、 'IEnumerable<SelectListItem>' 型である必要があります。

を使用しても同じエラーが発生します。 @Html.DropDownList() メソッドを使用してSelectListを渡すと、同じエラーが発生します。 ViewBag または ViewData .

どのように解決するのですか?

このエラーは CategoryList の値が null であることを意味します (その結果 DropDownListFor() メソッドは最初のパラメーターの型が IEnumerable<SelectListItem> ).

の各プロパティに対する入力を生成しているわけではありません。 SelectListItemCategoryList (の値はありません(そうすべきです)。 SelectList の値はコントローラのメソッドにポストされないので model.CategoryList は POST メソッドで null . ビューを返す場合は、最初に CategoryList の値を再割り当てしなければなりません。

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 はtypeof int にキャストすることはできません。 IEnumerable<SelectListItem> にキャストできず、例外が投げられます (これは MvcResources.resx ファイルで定義されています)。

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