Сложный объект и привязка модели ASP.NET MVC
У меня есть модельная структура объекта с классом Foo
, которая содержит Bar
со строковым значением.
public class Foo
{
public Bar Bar;
}
public class Bar
{
public string Value { get; set; }
}
И модель представления, которая использует эту структуру, подобную этой
public class HomeModel
{
public Foo Foo;
}
Тогда у меня есть форма, которая в Razor выглядит примерно так.
<body>
<div>
@using (Html.BeginForm("Save", "Home", FormMethod.Post))
{
<fieldset>
@Html.TextBoxFor(m => m.Foo.Bar.Value)
<input type="submit" value="Send"/>
</fieldset>
}
</div>
</body>
В html, который становится.
<form action="/Home/Save" method="post">
<fieldset>
<input id="Foo_Bar_Value" name="Foo.Bar.Value" type="text" value="Test">
<input type="submit" value="Send">
</fieldset>
</form>
Наконец, контроллер для обработки столбцов вроде этого
[HttpPost]
public ActionResult Save(Foo foo)
{
// Magic happends here
return RedirectToAction("Index");
}
Моя проблема в том, что Bar
в Foo
есть null
после того, как он попадает в действие контроллера Save
(Foo
создается, но с полем null
Bar
).
Я думал, что модельное связующее в MVC сможет создать объект Foo
и Bar
и установить свойство Value
, если оно выглядит так, как показано выше. Что мне не хватает?
Я также знаю, что моя модель просмотра немного сложна и может быть проще, но я за то, что я пытаюсь сделать, действительно помог бы мне, если бы мог использовать более глубокую структуру объекта. В приведенных выше примерах используется ASP.NET 5.
Ответы
Ответ 1
Во-первых, DefaultModelBinder
не привязывается к полям, поэтому вам нужно использовать свойства
public class HomeModel
{
public Foo Foo { get; set; }
}
Во-вторых, помощники генерируют элементы управления на основе HomeModel
, но вы отправляете обратно на Foo
. Либо измените метод POST на
[HttpPost]
public ActionResult Save(HomeModel model)
или используйте BindAttribute
, чтобы указать Prefix
(который, по существу, лишает значение префикса из опубликованных значений - поэтому Foo.Bar.Value
становится Bar.Value
для целей привязки)
[HttpPost]
public ActionResult Save([Bind(Prefix="Foo")]Foo model)
Обратите внимание также, что вы не должны указывать параметр метода с тем же именем, что и одно из ваших свойств, иначе привязка будет неудачной, а ваша модель будет пустой.
Ответ 2
Я только что обнаружил еще одну причину, которая может произойти, а именно, если ваше свойство называется Settings
! Рассмотрим следующую модель просмотра:
public class SomeVM
{
public SomeSettings DSettings { get; set; } // named this way it will work
public SomeSettings Settings { get; set; } // property named 'Settings' won't bind!
public bool ResetToDefault { get; set; }
}
В коде, если вы привязываетесь к свойству Settings
, он не может связываться (не только по почте, но даже при создании формы). Если вы переименуете Settings
в DSettings
(и т.д.), Он снова начнет работать снова.
Ответ 3
У меня была такая же проблема, и после того, как я последовал за шагами @Stephen Muecke, я понял, что проблема вызвана тем, что мои входы были отключены (я отключил их с помощью JQuery на готовом документе), как вы можете видеть здесь: Как отправить отключенный ввод в ASP.NET MVC?. В конце я использовал только для чтения, а не для отключенного атрибута, и все значения были успешно отправлены в контроллер.
Ответ 4
У меня была та же проблема, но как только я создал HIDDEN FIELD для внешнего ключа... все это работало отлично...
ПРИМЕР ФОРМЫ:
@using (Html.BeginForm("save", "meter", FormMethod.Post))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
@Html.HiddenFor(model => Model.Entity.Id)
@Html.HiddenFor(model => Model.Entity.DifferentialMeter.MeterId)
@Html.HiddenFor(model => Model.Entity.LinearMeter.MeterId)
@Html.HiddenFor(model => Model.Entity.GatheringMeter.MeterId)
... all your awesome controls go here ...
}
ПРИМЕР ДЕЙСТВИЯ:
// POST: /Meter/Save
[HttpPost]
public ActionResult Save(Meter entity)
{
... world-saving & amazing logic goes here ...
}
ДОСТОЙНЫЕ ИЗОБРАЖЕНИЯ:
![введите описание изображения здесь]()