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 теперь верно

Другие вопросы по тегам