Vor einer ganzen Weile habe ich schon über das Thema Modelbinding (oder wie übertrage ich Daten vom View zum Controller) geschrieben. Allerdings ist der Blogpost etwas älter und ging nur unzureichend auf komplexe Objekte und Auflistungen dieser ein.
Grundsatz: Das Modelbinding in ASP.NET MVC ist “relativ” clever und man kann fast alles binden. Man muss nur verstehen wie das Binding funktioniert und meist erklärt es sich, wenn man mal über Fiddler und co. nachschaut was per HTTP über die Leitung geht.
Objektmodell
public class Foobar { public string Buzz { get; set; } public int Foo { get; set; } public List<Foobar> Children { get; set; } }
Das Modell ist recht simpel, enthält aber als Liste wiederrum Objekte des selben Typs.
Action Method
Wir wollen die Daten an diesen Controller schicken (welcher im Grunde nichts damit macht – reicht aber für das Modelbinding Beispiel) :
public ActionResult Test(string name, List<Foobar> foobars) { return View("Index"); }
Ich stelle 3 Varianten vor, wie wir beliebig komplexe Objekte in diese Methode reinbekommen.
Variante 1: Einfache Form (Postback – kein AJAX)
@using (Html.BeginForm("Test", "Home", FormMethod.Post))
{
<input type="text" name="Name" value="Testvalue" />
<input type="text" name="Foobars[0].Buzz" value="Testvalue" />
<input type="text" name="Foobars[0].Foo" value="123123" />
<input type="text" name="Foobars[1].Buzz" value="Testvalue" />
<input type="text" name="Foobars[1].Foo" value="123123" />
<input type="text" name="Foobars[2].Buzz" value="Testvalue" />
<input type="text" name="Foobars[2].Foo" value="123123" />
<input type="text" name="Foobars[3].Buzz" value="Testvalue" />
<input type="text" name="Foobars[3].Foo" value="123123" />
<input type="text" name="Foobars[3].Children[0].Buzz" value="KIND!" />
<input type="text" name="Foobars[3].Children[0].Foo" value="123123" />
<button>Ok</button>
}
Über die “[ZAHL]” am Namen des Feldes weiß der MVC Binder, dass es sich um eine Liste handelt. Man kann das Ganze auch beliebig tief verschachteln. Wichtig ist an der Stelle, dass die Nummerierung durchgängig ist.
Wenn man sich anschaut was über die Leitung geht ist da auch nichts kompliziertes dran:
Variante 2: Formular via jQuery mit AJAX abschicken
Den Trick hatte ich bereits auch hier schon verraten, aber um bei dem oberen Beispiel zu bleiben:
$("#FormButton").click(function () { $.ajax({ url: "@Url.Action("Test", "Home")", type: "POST", data: $("form").serializeArray() }); });
Ich hänge mich an das Click-Event eines Buttons und hole mir alle Daten via “serializeArray()”. Auch hier schauen wir uns mal was über die Leitung geht. Wichtig ist hier, dass es vom Content-Type trotzdem nur Formulardaten sind – kein JSON:
Variante 3: Mit Javascript erstellte Daten – Javascript Arrays per AJAX übermitteln
Variante 1 und 2 gehen davon aus, dass es ein Formular gibt. Wenn man die Daten nur im Javascript zusammenbaut und auch keine “Hidden”-Form bauen möchte kann man diese Variante nutzen.
$("#ScriptButton").click(function () { var foobars = new Array(); for (i = 0; i < 10; i++) { foobars.push({ Buzz: "Test!", Foo: 12123, Children: { Buzz: "Child!", Foo: 123213} }); } var requestData = { }; requestData.Name = "Testadalsdk"; requestData.Foobars = foobars; $.ajax({ url: "@Url.Action("Test", "Home")", type: "POST", contentType: 'application/json;', dataType: 'json', data: JSON.stringify(requestData) }); });
Im ersten Schritt erstellen wir uns ein Array im Javascript:
Dann erstellen wir uns “requestData” und setzen unser “Name”-Testproperty und hängen zusätzlich das Array daran.
Um dies jetzt an unseren Controller zu übermitteln müssen wir die Daten umwandeln. Am einfachsten gelingt dies über das JSON-Format. Neuere Browser haben eine native JSON Unterstützung, aber um sicher zu gehen empfiehlt es sich den JSON Helper von Douglas Crockford “json2.js” zu nehmen (gibt auch via NuGet).
Über dieses Script bekommt man die Methode “JSON.stringify()” (Link führt zum Mozilla Developer Center – dasselbe steht aber im Prinzip auch in der MSDN), welches ein Objekt in JSON umwandelt.
Dazu setzen wir im AJAX Request noch zusätzlich diese Propertys, damit unser Controller auch versteht was da überhaupt ankommt:
contentType: 'application/json;',
dataType: 'json',
Dies fliesst am Ende über die Leitung:
Durch den Content-Type: application/json nutzt das MVC Framework automatisch den JSON Modelbinder und die Daten kommen im Controller an.
Fazit
Man kann fast alles mit dem MVC Modelbinding machen wenn man ein paar Grundregeln beherrscht und ein Blick, was wirklich per HTTP übertragen wird hilft beim Debugging enorm.
Die gesamte Demoapplikation findet ihr hier – allerdings ist da auch noch Code drin von diesem Blogpost.