'XXX' anahtarına sahip ViewData öğesi 'System.Int32' türünde ancak 'IEnumerable <SelectListItem>' türünde olmalıdır


114

Aşağıdaki görünüm modeline sahibim

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

ve yeni bir Proje oluşturmak ve bir 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
}

ve görünümde

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

Görünüm düzgün görüntüleniyor ancak formu gönderirken aşağıdaki hata mesajını alıyorum

InvalidOperationException: 'CategoryID' anahtarına sahip ViewData öğesi 'System.Int32' türünde ancak 'IEnumerable <SelectListItem>' türünde olmalıdır.

Aynı hata @Html.DropDownList()yöntemi kullanırken ve SelectList'i a ViewBagveya ViewData.

Yanıtlar:


110

Hata, değerinin CategoryList boş olduğu anlamına gelir (ve sonuç olarak DropDownListFor()yöntem, ilk parametrenin türde olmasını bekler IEnumerable<SelectListItem>).

Her her özellik için bir giriş getirmeyen SelectListItemolarak CategoryList(ve ne de gerekir) için değer, böylece SelectListkontrol yöntemine yayınlanmıştır ve dolayısıyla değeri vardır model.CategoryListPOST yöntemidir de null. Görünümü geri döndürürseniz CategoryList, GET yönteminde yaptığınız gibi önce değerini yeniden atamanız gerekir .

public ActionResult Create(ProjectVM model)
{
    if (!ModelState.IsValid)
    {
        model.CategoryList = new SelectList(db.Categories, "ID", "Name"); // add this
        return View(model);
    }
    // Save and redirect
}

İç işleyişi açıklamak için (kaynak kodu burada görülebilir )

Her aşırı yükleme DropDownList()ve DropDownListFor()sonunda aşağıdaki yöntemi çağırır

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

selectList(ikinci parametresinin @Html.DropDownListFor()) olup olmadığını kontrol edernull

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

hangi sırayla çağırır

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

ilk parametresini değerlendiren @Html.DropDownListFor()(bu durumda 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>"));
}

Özellik CategoryIDtypeof olduğundan int, dönüştürülemez IEnumerable<SelectListItem>ve istisna atılır ( MvcResources.resxdosyada şu şekilde tanımlanır )

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

8
@Shyju, Evet, yanıtlanmamış veya kabul edilmemiş olarak kalan diğer pek çok benzer soruyu SO'da tekrarlamak amacıyla sordum ve yanıtladım (topluluk wiki olarak). Ama intikam seçmenlerinin çoktan başladığını görüyorum - ilki yayınlandıktan sonra 2 saniyeden azdı - yanıtı bırakın, onu okumak için bile yeterli zaman yoktu.

1
Anlıyorum. Aynı soruna sahip 100 soru var. Genellikle bu soruları soran kişiler uygun arama yapmazlar (veya mevcut bir yanıtı kelime kelime kopyalayıp yapıştırırlar, ancak işe yaramadı!) Bu yüzden bunun gerçekten yardımcı olabileceğinden emin değilim. :) Güzel yazılmış BTW.
Shyju

@Stephen bu doğru değil, soruyorsun ve cevap
veriyorsun

8
@DilipN, Doğru yol değil ne demek istiyorsun ? Aslında SO'da teşvik ediliyor. Sen okumalı bu ve meta üzerinde biraz zaman harcamak.

4
@DilipN, Çünkü bunu, çok sayıda benzer soruyu ya cevaplanmamış ya da cevaplanmış ancak kapatılabilmeleri için kabul edilmeyen yinelenen sorular olarak işaretlemek için kullanacağım (böylece diğerleri zamanlarını boşa harcamayacaklar). Ayrıca onu bir topluluk wiki yaptım, böylece herkes zaman içinde onu düzenleyebilir ve geliştirebilir.

6

stephens (user3559349) cevabına göre , bu yararlı olabilir:

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

veya ProjectVM'de:

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

1

Muhtemelen sayfanıza yönlendirmede bir tür hataya neden oldu ve modelinizin açılır listelerini yeniden başlatmıyorsunuz.

Açılır listenizi modelin yapıcısında veya söz konusu modeli sayfaya her göndermeden önce başlattığınızdan emin olun.

Aksi takdirde, açılır listelerin durumunu görüntüleme çantası veya gizli değer yardımcıları aracılığıyla korumanız gerekecektir.


0

Aynı sorunu yaşadım, formu göndermeye çalıştığımda geçersiz bir ModelState alıyordum. Benim için bu, ModelState geçerliydi ve Create yöntemi beklendiği gibi çalıştığında, CategoryId'nin int olarak ayarlanmasından kaynaklanıyordu.


0

Tamam, posterin hazır cevabı nedenini düzgünce açıkladı hatanın oluştuğunu , ancak nasıl çalıştırılacağını . Bunun gerçekten bir cevap olduğundan emin değilim, ama beni doğru yönü gösterdi.

Ben de aynı sorunla karşılaştım ve çözmenin düzgün bir yolunu buldum. Bunu burada yakalamaya çalışacağım. Sorumluluk reddi - Yılda bir kez web sayfalarında çalışıyorum ve çoğu zaman ne yaptığımı gerçekten bilmiyorum. Bu cevap hiçbir şekilde "uzman" bir cevap olarak görülmemelidir, ancak işi çok az işle yapar ...

Bir alan için geçerli değerler sağlamak üzere bir açılır liste kullanmak istediğim bazı veri nesnelerine (büyük olasılıkla bir Veri Aktarım Nesnesi) sahip olduğum için:

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

Ardından ViewModel şöyle görünür:

public class MyDataObjectVM
{
  public int id;

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

@Stephen'ın yukarıda çok net bir şekilde açıklandığı gibi buradaki asıl sorun, seçme listesinin denetleyicideki POST yönteminde doldurulmamasıdır. Yani denetleyici yöntemleriniz şöyle görünür:

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

İşte aldın. Bu çalışma kodu DEĞİL, basitleştirmek için kopyaladım / yapıştırdım ve düzenledim, ancak fikri anladınız. Hem orijinal veri modelindeki hem de türetilmiş görünüm modelindeki veri üyeleri aynı ada sahipse, UpdateModel () FormCollection değerlerinden sizin için doğru verileri doldurarak harika bir iş çıkarır.

Bunu buraya gönderiyorum, böylece kaçınılmaz olarak bu konuyla tekrar karşılaştığımda cevabı bulabilirim - umarım başka birine de yardımcı olur.


0

Benim durumumda, listemdeki ilk kimlik sıfırdı, kimliği 1'den başlayacak şekilde değiştirdiğimde işe yaradı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.