Подтвердить что ты не робот

Сложный объект и привязка модели 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.

4b9b3361

Ответ 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 ...
}

ДОСТОЙНЫЕ ИЗОБРАЖЕНИЯ:
введите описание изображения здесь