Ошибка означает, что значение CategoryList
равно нулю (и в результате метод DropDownListFor()
ожидает, что первый параметр имеет тип IEnumerable
).
Вы не генерируете вход для каждого свойства каждого 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 selectList, bool allowMultiple,
IDictionary 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 GetSelectData(this HtmlHelper htmlHelper, string name)
, который оценивает первый параметр @Html.DropDownListFor()
(в данном случае CategoryID
)
....
o = htmlHelper.ViewData.Eval(name);
....
IEnumerable selectList = o as IEnumerable;
if (selectList == null)
{
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
MvcResources.HtmlHelper_WrongSelectDataType,
name, o.GetType().FullName, "IEnumerable"));
}
Поскольку свойство CategoryID
является typeof int
, оно не может быть передано в IEnumerable
, и генерируется исключение (которое определено в файле MvcResources.resx
как)
The ViewData item that has the key '{0}' is of type '{1}' but must be of type '{2}'.
#pragma message ("Warning goes here")
На заметке, если вы хотите подавить такие предупреждения, найдите идентификатор предупреждения компилятора (для устаревшего предупреждения это C4996
) и вставьте эту строку:
#pragma warning( disable : 4996
)
Несмотря на то, что нет стандарта #warning
#warning Наимера, многие компиляторы (включая GCC, VC, INTELS и яблоки), поддержку #warning Message
.
#warning "this is deprecated"
Часто лучше принять предупреждение о том, что люди могут упускать из виду), но чтобы полностью компилировать неудачу, используя директиву #Error
(что является стандартным):
#if !defined(FOO) && !defined(BAR)
# error "you have neither foo nor bar set up"
#endif
Как новичок, назначенный для выполнения исправлений ошибок, я обнаружил, что конкретная ошибка, которую я был назначен, была печать (для отладки) «Это никогда не должно произойти». После того, как преодолел свой страх работы в условиях ошибки, что, по-видимому, было невозможно, мне наконец удалось обнаружить, что это было вызвано тонким состоянием расы. Если автор этого кода изначально прославил исключение, несмотря на то, что не менее, по крайней мере, что скудное отладочное утверждение, было бы намного сложнее отследить состояние гонки.
С тех пор я стал огромным сторонником либо предприниматься с исключениями или предпринимающими их до тех пор, пока состояние ошибки не будет отображаться пользовательским дружеским способом к конечному пользователю, шаг дальше от простого регистрации оператора отладки.
-121--1262022-, чтобы отметить функцию как устаревшее, используйте __ DELSSPEC (устарели)
, например.
__declspec(deprecated) void f();