Страницы

Поиск по вопросам

воскресенье, 9 июня 2019 г.

Ошибка биндинга - приходит пустая модель

Есть два метода для редактирования
Первый передает значения для редактирования, а второй редактирует
public ActionResult EditMagazine(int id) { var editMagazineModel = new EditMagazineViewModel() { Magazine = magazineService.EditMagazine(id) }; return View(editMagazineModel); } [HttpPost] [ValidateAntiForgeryToken] public ActionResult EditMagazine1(EditMagazineViewModel magazine) { var magazineModel = new Magazine { MagazineId = magazine.Magazine.MagazineId, Name = magazine.Magazine.Name, Number = magazine.Magazine.Number, YearOfPublishing = magazine.Magazine.YearOfPublishing }; magazineService.EditMagazine1(magazineModel); return RedirectToAction("Magazine"); }
из-за того что делаю ViewModel пришлось столкнуться с mapping'ом ,
так вот проблема в том что во втором методе выходит исключение из-за этого
var magazineModel = new Magazine {
я создаю новый обьект
Кто подскажет как правильно передать значения с первого метода для второго метода
[NullReferenceException: Object reference not set to an instance of an object.]
Вот ViewModel
public class EditMagazineViewModel { public Magazine Magazine { get; set; } }
а вот Model
public class Magazine { public int MagazineId { get; set; } public string Name { get; set; } public int Number { get; set; } public int YearOfPublishing { get; set; } }
Вот View EditMagazine
@model Library.ViewModel.MagazineViewModel.EditMagazineViewModel
@{ Layout = "~/Views/Home/Layout.cshtml"; }

@using (Html.BeginForm("EditMagazine1", "Magazine"))
{
@Html.AntiForgeryToken()

Magazine


@Html.ValidationSummary(true, "", new { @class = "text-danger" }) @Html.HiddenFor(model => model.Magazine.MagazineId)
@Html.LabelFor(model => model.Magazine.Name, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.Magazine.Name, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Magazine.Name, "", new { @class = "text-danger" })

@Html.LabelFor(model => model.Magazine.Number, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.Magazine.Number, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Magazine.Number, "", new { @class = "text-danger" })

@Html.LabelFor(model => model.Magazine.YearOfPublishing, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.Magazine.YearOfPublishing, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Magazine.YearOfPublishing, "", new { @class = "text-danger" })

}


Ответ

Ваша модель основана на простых типах типа int и string:
public class Magazine { public int MagazineId { get; set; } public string Name { get; set; } public int Number { get; set; } public int YearOfPublishing { get; set; } }
При этом вы могли пойти по пути использования модели в качестве ViewModel - но раз уж вы пошли по пути ухода от модели - то не надо было во вьюмодели ссылаться на доменную логику:
public class EditMagazineViewModel { public Magazine Magazine { get; set; } }
Сделайте класс на простых типах:
public class EditMagazineViewModel { public int MagazineId { get; set; } public string Name { get; set; } public int Number { get; set; } public int YearOfPublishing { get; set; } }
(Чувствуете, что хочется записаться в сторонники использования моделей в качестве вьюмоделей? Код копипастится)
Давайте теперь переделаем наш первый action:
public ActionResult Edit(int id) { var magazine = magazineService.GetById(id); var model = new EditMagazineViewModel(magazine); return View(model); }
и второй:
[HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit(EditMagazineViewModel model) { if (!this.ModelState.IsValid) return this.View(model);
var magazine = model.ToEntity(); magazineService.Update(magazine); return RedirectToAction("Magazine"); }
(Обратите внимание: в сервис мы передаём уже доменную модель, сервис относится к слою бизнес-логики и может ничего не знать о десятках приложений (веб, мобильных) у каждого свои собственные вьюмодели)
Только для этого нам нужно класс модели переписать следующим образом:
public class EditMagazineViewModel { public EditMagazineViewModel() { }
public EditMagazineViewModel(Magazine magazine) { this.MagazineId = magazine.MagazineId; this.Name = magazine.Name; this.Number = magazine.Number; this.YearOfPublishing = magazine.YearOfPublishing; }
public Magazine ToEntity() { return new Magazine { MagazineId = this.MagazineId, Name = this.Name, Number = this.Number, YearOfPublishing = this.YearOfPublishing, }; }
public int MagazineId { get; set; } public string Name { get; set; } public int Number { get; set; } public int YearOfPublishing { get; set; } }
Первый конструктор нужен для asp.net, второй - для нас (чтобы не разбухал метод контроллера), а ToEntity - преобразует обратно ViewModel в Model.
Понадобится - можете потом подтащить мапперы вместо этих методов.
Остаётся переписать view:
@model Library.ViewModel.MagazineViewModel.EditMagazineViewModel @{ Viewbag.Title = "Edit magazine"; }

@Viewbag.Title

@using (Html.BeginForm("EditMagazine", "Magazine", FormMethod.Post)) { @Html.AntiForgeryToken()
@Html.ValidationSummary(true, "", new { @class = "text-danger" }) @Html.HiddenFor(model => model.MagazineId)
@Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.Number, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.Number, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Number, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.YearOfPublishing, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.YearOfPublishing, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.YearOfPublishing, "", new { @class = "text-danger" })
}
У меня в тестовом приложении работает (естественно чуть другие неймспейсы), проблем нет:

Комментариев нет:

Отправить комментарий