키가 'XXX'인 ViewData 항목은 'System.Int32'유형이지만 'IEnumerable'유형이어야합니다.<selectlistitem>'</selectlistitem>

c# asp.net-mvc


다음과 같은 뷰 모델이 있습니다

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 : 'CategoryID'키가있는 ViewData 항목은 'System.Int32'유형이지만 'IEnumerable <SelectListItem>'유형이어야합니다.

@Html.DropDownList() 메서드를 사용하고 ViewBag 또는 ViewData 를 사용하여 SelectList를 전달하면 동일한 오류가 발생합니다 .




Answer 1 user3559349


이 오류는 CategoryList 의 값 이 null 임을 의미합니다. 결과적으로 DropDownListFor() 메서드는 첫 번째 매개 변수가 IEnumerable<SelectListItem> 유형 인 것으로 예상합니다 .

각 각 속성에 대한 입력을 생성하지 SelectListItemCategoryList (및 없으며해야한다)에 대한 값이되도록 SelectList 제어기 방법에 등록한없고, 따라서 가치있다 model.CategoryList POST 메소드에가 null . 뷰를 리턴 하면 GET 메소드에서와 마찬가지로 먼저 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>



Answer 2 Omid-RH


stephens (user3559349) answer에 따르면 다음과 같이 유용 할 수 있습니다.

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

또는 ProjectVM에서 :

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



Answer 3 Gavin Rotty


가장 가능성이 큰 원인이 페이지로 리디렉션되는 오류가 발생하여 모델의 드롭 다운 목록을 다시 초기화하지 않은 것입니다.

모델 생성자에서 또는 해당 모델을 페이지로 보내기 전에 매번 드롭 다운을 초기화해야합니다.

그렇지 않으면 뷰백 또는 숨겨진 값 도우미를 통해 드롭 다운 목록의 상태를 유지해야합니다.




Answer 4 ardmark


같은 문제가 발생하여 양식을 게시하려고 할 때 잘못된 ModelState가 발생했습니다. 나에게 이것은 CategoryId를 int로 설정했기 때문에 발생했습니다 .ModelState가 문자열로 변경되고 Create 메서드가 예상대로 작동했습니다.




Answer 5 DaveN59


좋아, 포스터의 통조림 답변 은 오류가 발생한 이유를 깔끔하게 설명 했지만 어떻게 작동시키는지는 설명하지 못했습니다. 나는 그것이 실제로 답인지 확신하지 못하지만 올바른 방향으로 나를 가리 켰습니다.

나는 같은 문제에 부딪 쳤고 그것을 해결하는 매끄러운 방법을 발견했다. 나는 그것을 여기에서 포착하려고 노력할 것입니다. 면책 조항-일년에 한 번 정도 웹 페이지에서 작업하며 대부분의 시간을 실제로 알지 못합니다. 이 답변은 결코 "전문가"답변으로 간주되어서는 안되지만, 별다른 노력을 기울이지 않아도됩니다.

드롭 다운 목록을 사용하여 필드에 유효한 값을 제공하려는 일부 데이터 오브젝트 (대부분 데이터 전송 오브젝트)가 있다고 가정하면 다음과 같습니다.

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

그런 다음 ViewModel은 다음과 같습니다.

public class MyDataObjectVM
{
  public int id;

  public string StrValue;
  public List<SectListItem> strValues;
}

@Stephen이 위에서 웅변 적으로 설명했듯이 여기서 실제 문제는 컨트롤러의 POST 메소드에서 선택 목록이 채워지지 않는다는 것입니다. 따라서 컨트롤러 메소드는 다음과 같습니다.

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

거기 있어요 이것은 작동 코드가 아니며 간단하게 복사 / 붙여 넣기 및 편집했지만 아이디어를 얻었습니다. 원래 데이터 모델과 파생 된 뷰 모델의 데이터 멤버가 동일한 이름을 갖는 경우 UpdateModel ()은 FormCollection 값에서 올바른 데이터 만 채 웁니다.

필자는이 문제를 다시 겪을 때 대답을 찾을 수 있도록 여기에 게시하고 있습니다. 다른 사람에게도 도움이되기를 바랍니다.