ASP.NET MVC 4 "Создать" приводит к отправке страницы в недействительном ModelState
У меня проблема, возможно, только из-за отсутствия у меня опыта работы с ASP.NET MVC, но эту проблему я уже пытался решить немного.
У меня есть база данных Code First, которая не сильно отличается от первого учебника на asp.net ( http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/intro-to-aspnet-mvc-4). В основном проблема, с которой я сталкиваюсь, заключается в том, что при попытке создать новую запись в базе данных через страницу "Создать" идентификатор устанавливается равным 0, что делает недействительным ModelState.
Соответствующий код: Модель:
public class Evt
{
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string GeoDescription { get; set; }
public decimal Longitude { get; set; }
public decimal Latitude { get; set; }
public DateTime Date { get; set; }
}
контроллер:
[HttpPost]
public ActionResult Create(Evt evt)
{
if (ModelState.IsValid) // This is returning false because ID is 0
{
db.Evts.Add(evt);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(evt);
}
Я также могу добавить код View по запросу, но в основном это просто сгенерированный код из модели.
Если у кого-то есть идеи, я буду очень признателен!
Спасибо,
Джефф
Редактировать: я вообще не ссылаюсь на идентификатор в моем представлении "Создать", и добавление его в качестве скрытого значения формы также не решило мою проблему.
Обновление: я смог обойти ошибку, добавив
if (!ModelState.IsValid && evt.ID == 0) ModelState.Clear();
выше if
заявление в Create
, но это удаляет все проверки на стороне клиента и, очевидно, не идеально. Это показывает, что запись правильно вставлена с увеличенным идентификатором, как только она попадает на сервер.
4 ответа
Если кто-то столкнется с этим в будущем, возможно, это не тот ответ, который вы хотели бы услышать, но это то, что я в итоге сделал.
Я переключился на использование явного Entity Framework (Database First) вместо использования Code First. Это заново сгенерировало мою модель и впоследствии решило мою проблему. Я не совсем уверен, почему он это исправил, но, как я сказал в описании проблемы, я думаю, что это, возможно, был незначительный параметр или строка кода, которую я случайно изменил изначально.
Мое предложение для тех, кто имеет эту проблему и не хочет отказываться от Code First: попробуйте рефакторинг вашей модели или ее полное удаление и создание новой с теми же свойствами.
Извините, я не могу помочь.
Похоже, вы используете ваши классы EF Entity в качестве ViewModels. Это не рекомендуется, потому что не существует сопоставления 1:1 между ViewModels (которые инкапсулируют содержимое данных формы ввода, удобочитаемой для человека) и сущностями (которые представляют нормализованные бизнес-объекты), просто случайно можно обойтись без использования простого EF классы как ViewModels, но если вы это сделаете, в конечном итоге вы столкнетесь с такими проблемами.
Есть несколько возможных решений, лучше всего использовать выделенную ViewModel для вашей страницы. Во-вторых, изменить свой класс сущности, чтобы изменить int ID
в int? ID
поэтому связыватель моделей не будет требовать указания элемента, третий вариант - очистить диктонник состояния модели от любых ошибок, связанных с ID
член до вызова ModelState.IsValid
,
Обратите внимание, что если вы продолжите использовать свои классы сущностей в качестве моделей представления, вы будете подвержены атакам Mass Assignment (как ваш код в настоящее время). Вот почему выделенные ViewModels для каждого вида являются лучшими.
Как говорит Дай, рекомендуемый подход состоит в том, чтобы не использовать ваши сущности непосредственно в вашем представлении. Для этого есть много причин, но вы уже сейчас их чувствуете.
Однако, если вы не собираетесь этого делать, у вас есть несколько вариантов. Вы можете очистить состояние модели, как говорит Дай, но мне не нравится этот подход. Это нахально и безобразно, а на самом деле это просто плохая практика.
Вы также можете добавить [Bind(Exclude="ID")]
к вашему параметру. В этом случае:
public ActionResult Create([Bind(Exclude="ID")] Evt evt)
Мне это тоже не очень нравится, но, по крайней мере, это не так страшно, как удаление элемента из ModelState в вашем контроллере.
Вы также можете добавить скрытое поле. Вы говорите, что сделали это, и это не решило проблему, но это должно было сработать. Поэтому, возможно, вы что-то делали неправильно, например, использовали неправильное соглашение об именах. Я предлагаю использовать HiddenFor
и убедитесь, что это в пределах скобок вашего BeginForm(){}
@Html.HiddenFor(x => x.ID)
Я просто сталкивался с этой проблемой, не уверен, что то же самое для вас
Я использую ту же страницу для New и Edit, поэтому у меня есть что-то вроде:
@Html.HiddenFor(model => model.Code_Id)
но это полезно только для редактирования, поэтому я добавляю что-то вроде:
if (ViewBag.Action != "New")
{
@Html.HiddenFor(model => model.Code_Id)
}
и ModelState.IsValid теперь верно