web-dev-qa-db-de.com

ASP.NET MVC für komplexe Objekte und Modelle

Ich habe eine Modellobjektstruktur mit einer Foo-Klasse, die eine Bar mit einem Zeichenfolgenwert enthält.

public class Foo
{
    public Bar Bar;
}

public class Bar
{
    public string Value { get; set; }
}

Und ein Ansichtsmodell, das diese Struktur wie folgt verwendet

public class HomeModel
{
    public Foo Foo;
}

Ich habe dann ein Formular im Blick, das in Razor so aussieht.

<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>

In HTML wird das.

<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>

Zum Schluss der Controller, um die Post-Loos so zu handhaben

[HttpPost]
public ActionResult Save(Foo foo)
{
    // Magic happends here
    return RedirectToAction("Index");
}

Mein Problem ist, dass Bar in Foonull ist, sobald die Save-Controller-Aktion getroffen wird (Foo wird erstellt, jedoch mit einem nullBar-Feld).

Ich dachte, der Modellbinder in MVC würde in der Lage sein, das Foo- und das Bar-Objekt zu erstellen und die Value -Eigenschaft festzulegen, solange es wie oben aussieht. Was vermisse ich?

Ich weiß auch, dass mein Ansichtsmodell etwas kompliziert ist und einfacher sein könnte, aber ich würde mir wirklich helfen, wenn ich die tiefere Objektstruktur verwenden könnte. Die obigen Beispiele verwenden ASP.NET 5.

28
Riri

Erstens wird DefaultModelBinder nicht an Felder gebunden, daher müssen Sie Eigenschaften verwenden

public class HomeModel
{
  public Foo Foo { get; set; }
}

Zweitens generieren die Helfer Steuerelemente basierend auf HomeModel, aber Sie buchen zurück zu Foo. Ändern Sie die Methode POST in 

[HttpPost]
public ActionResult Save(HomeModel model)

oder verwenden Sie die Variable BindAttribute, um die Variable Prefix anzugeben (wodurch der Wert des Präfixes im Wesentlichen von den angegebenen Werten entfernt wird - aus Foo.Bar.Value wird Bar.Value für Bindungszwecke).

[HttpPost]
public ActionResult Save([Bind(Prefix="Foo")]Foo model)

Beachten Sie auch, dass Sie den Methodenparameter nicht mit dem gleichen Namen wie eine Ihrer Eigenschaften benennen sollten, da sonst die Bindung fehlschlägt und Ihr Modell null ist.

36
user3559349

Ich habe gerade einen anderen Grund entdeckt, warum dies passieren kann, wenn Ihre Eigenschaft Settings heißt! Betrachten Sie das folgende View-Modell:

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; }
}

Wenn Sie im Code an die Settings-Eigenschaft binden, schlägt die Bindung fehl (nicht nur auf dem Postweg, sondern auch beim Generieren des Formulars). Wenn Sie Settings in DSettings (etc) umbenennen, funktioniert es plötzlich wieder.

3

Ich hatte das gleiche Problem, und nachdem ich die Schritte von @Stephen Muecke befolgt hatte, stellte ich fest, dass das Problem dadurch verursacht wurde, dass meine Eingaben deaktiviert waren (ich habe sie mit JQuery für Dokumente deaktiviert), wie Sie hier sehen können: Wie kann ich gesperrte Eingaben in ASP.NET MVC senden? . Am Ende habe ich schreibgeschützt anstelle von deaktivierten Attributen verwendet und alle Werte wurden erfolgreich an die Steuerung gesendet.

0
joalcego

Ich hatte das gleiche Problem, aber als ich einmal ein HIDDEN FIELD für den Fremdschlüssel erstellt hatte, funktionierte alles einwandfrei ...

FORM BEISPIEL: 

@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 ...
}

AKTIONSBEISPIEL: 

// POST: /Meter/Save
[HttpPost]
public ActionResult Save(Meter entity)
{
    ... world-saving & amazing logic goes here ...
}

SCHÖNE BILDER: 
 enter image description here

0
Prisoner ZERO