Надлежащая маршрутизация действий «Отменить» и «Сохранить»

У меня есть страница со списком всех велосипедов (Bike.cshtml). При нажатии на отдельный велосипед я перенаправляюсь на страницу редактирования (BikeEdit.cshtml). Внизу редактора у меня есть две ссылки.

@Html.ActionLink("Cancel", "Bikes", "Home")
@Html.ActionLink("Update", "Bikes", "Home")

Оба случая должны вести обратно к странице со списком велосипедов. Очевидно, во втором я хочу сохранить изменения объекта модели в БД. У меня возникает соблазн решить эту проблему, отправив модель вот так.

@Html.ActionLink("Cancel", "Bikes", "Home")
@Html.ActionLink("Update", "Bikes", "Home", @Model, null)

Тем не менее, я чувствую, что есть лучший способ справиться с этим. Что-то настораживает управление сохранением с контроллера вьювера байков.

Другой подход, который я могу придумать, состоит в том, чтобы добавить новое действие BikeSave и выполнить в нем сохранение. Однако возвращенный экземпляр представления будет основан не на Bikes.cshtml, а на BikeSave.cshtml. Я могу представить, что мог бы использовать RedirectToAction, но я не уверен. Я не хочу проектировать что-то, используя «клейкую ленту».

Вот и ломаю голову, не могу определиться...


person Community    schedule 01.01.2016    source источник
comment
Почему бы вам не использовать метод Post для редактирования (при условии, что у вас есть метод Get)?   -  person Frank Fajardo    schedule 02.01.2016
comment
Не могли бы вы объяснить немного больше, пожалуйста? Вы имеете в виду, что я должен обрабатывать как сохранение, так и отображение в Bikes.cshtml?   -  person    schedule 02.01.2016


Ответы (1)


Когда пользователь нажимает кнопку обновления, вы должны отправить форму в свой метод действия HttpPost, где вы обновите свою базу данных, а затем перенаправите на страницу Home/Bikes.

Предполагая, что ваше действие GET похоже на это

public ActionResult BikeEdit(int id)
{
  var bikeEditVm=new BikeEditVm { Id=id};
  var bikeEntity = db.Bikes.FirstOrDefault(s=>s.Id==id);
  if(bikeEntity!=null)
  {
    bikeEditVm.ModelName=bikeEntity.ModelName;
    bikeEditVm.Color=bikeEntity.Color;   
    return View(bikeEditVm); 
  }
  return View("NotFound"); // return a bike not found view to user
}

Где BikeEditVm — это модель представления для редактирования, которая выглядит так

public class BikeEditVm
{
  public int Id {set;get;}
  public string ModelName {set;get;}
  public string Color {set;get;}
}

В вашем представлении, строго типизированном для BikeEditVm, вы сохраните все свои редактируемые поля внутри тега form.

@model BikeEditVm
@using(Html.BeginForm())
{
  <label>ModelName</label>
  @Html.TextBoxFor(s=>s.ModelName)
  <label>Color</label>
  @Html.TextBoxFor(s=>s.Color)
  @Html.HiddenFor(s=>s.Id)
  <input type="submit" value="Update" />
}
@Html.ActionLink("Cancel","Bikes","Home")

У вас будет метод HttpAction для обработки публикации формы, где вы будете читать существующий объект из базы данных, обновлять соответствующие поля, которые хотите обновить, и сохранять их обратно.

[HttpPost]
public ActionResult BikeEdit(BikeEditVm model)
{
  var bikeEntity = db.Bikes.FirstOrDefault(s=>s.Id==model.id);
  if(bikeEntity!=null)
  {
    bikeEntity .ModelName = model.ModelName;
    bikeEntity .Color = model.Color;   
    db.Entry(bikeEntity).State=EntityState.Modified;
    db.SaveChanges();
    return RedirectToAction("Bikes","Home");
  }
  return View("NotFound");
}

EDIT: Отвечаю на некоторые вопросы, которые ОП задал в комментариях для будущих читателей.

(1) Я проверил, чтобы пропустить [HttpPost], и он все еще работает. Должен ли?

Все, что обновляет ваши данные, должно быть методом HttpPost. В противном случае люди могут получить доступ к вашему методу действия через URL-адрес (метод GET) и передать значения имени поля формы и попытаться обновить ваши данные. (Ваши проверки авторизации могут предотвратить это. если существует)

(2) Как ваш Html.BeginForm() знает, куда направлять? Я использую Html.BeginForm (действие, контроллер).

Если вы не передадите никаких аргументов методу BeginForm, он установит значение действия формы в качестве текущего URL-адреса. Пример: если вы находитесь в представлении действия клиента/создания GET, ваша форма будет опубликована для клиента/создания. Вы можете переопределить это поведение, используя другую перегрузку, в которой вы можете указать другое имя метода/контроллера действия.

(3) Если я хочу, чтобы поле было передано вверх/вниз, но не было редактируемым/видимым, должен ли я использовать CSS, чтобы скрыть его? Было бы хорошо иметь контроль над хранением вне экрана.

Если вы не хотите, чтобы поле было редактируемым/видимым, не передавайте его в ваше представление. Имейте только те свойства в вашей модели представления, которые вам действительно нужны в вашем представлении. Прочитайте следующий ответ о том, как предотвратить чрезмерную публикацию.

(4) Является ли вообще лучшей идеей иметь специализированную модель для представления вместо использования модели из EF?

Это. Если вы используете классы сущностей, созданные вашей ORM, для передачи данных между вашим методом действия и представлением, вы создаете тесно связанное решение. Что, если вы по какой-либо причине решите завтра не использовать EF в качестве уровня доступа к данным? Вы хотите пойти и обновить все ваши взгляды? Ваши модели представления специфичны для представления. Поэтому оставьте только те свойства/поля, которые необходимы для представления. Это также поможет вам предотвратить чрезмерную публикацию.

person Shyju    schedule 02.01.2016