Da ich aktuell fröhlich ASP.MVC nutzen darf, bin ich über ein Problem gestoßen, zu dem ich nur bedingt hilfreiche Unterstützung im Web gefunden habe. Genauer geht es darum, dass ich mir in meiner View, mit Javascript ein Json-Objekt zusammen baue und dieses dann über ein Formular an den Controller übertragen werden muss.

Zu Darstellungszwecken möchte ich das Beispiel etwas kleiner halten als es tatsächlich ist und mir den Teil sparen bei dem ich das Json-Objekt dynamsich aufbaue. Gesagt sei nur so viel, dass es notwendig wurde dieses Objekt aufzubauen, weil es ursprünglich aus mehreren Eingabefeldern vom Nutzer zu einem Baum zusammengesetzt wurde.

var personen = {
„Name“: „Peter,
„Alter“: 63,
„Kinder“: [
„Franz“,
„Margitta“
]
}

Das Formular mit dem die Daten übertragen wurden sieht dann in etwa so aus:

@using (Html.BeginForm("StartSuche", "ErgebnisListe", FormMethod.Post))
{
    @Html.HiddenFor(model => model.Personen)
                <div class="row">
                    <div class="col-md-3" align="right">
                        @Html.DisplayNameFor(model => model.Id)
                    </div>
                    <div class="col-md-5">
                        @Html.Kendo().MaskedTextBoxFor(model => model.Id).HtmlAttributes(new { style = "width:340px" })
                    </div>
                </div>
	...
                    <div class="row">
                        <div class="col-md-3">Personen:</div>
                        <div class="col-md-7" >
                            @(Html.Kendo().TreeView())
                        </div>
                    </div>
        <div class="row">
            <div class="col-md-12">
                <button id="sucheStarten" class="btn btn-default" type="submit">
                    Ergebnis anzeigen
                </button>
            </div>
        </div>
    </div>      
}

Darin finden wir auch schon den ersten Hinweis auf die Lösung unseres Problems. Indem wir das Hiddenfield in das Formular schreiben, können wir in diesem all die Daten hinterlegen, die für uns nicht über ein standardmäßiges Steuerelement hinterlegt werden können. Dazu müssen wir nur an geeigneter Stelle ein wenig JQuery bemühen. Wenn wir dem Model von oben gefolgt sind, können wir als Id des Feldes den Namen der Eigenschaft nehmen gegen die wir das Feld gebunden haben.

$("#Personen").val(JSON.stringify(personen));

Damit hätten wir die halbe Miete schon mal drin, bloß können wir damit bisher nichts anfangen. Was uns noch fehlt ist eine Möglichkeit die Daten in unser Model zu bekommen. Der einfachste, bei weitem aber nicht sauberste Weg besteht darin uns die Daten aus dem HiddenField zu laden, zu deserialisieren und dann weiter zu verwenden. Dieses „Laden aus dem HiddenField“ realisieren wir in der ActionMethode unseres Controllers über die Klasse Request, welche einen Stringindexer „Form“ besitzt, den wir mit dem Namen des HiddenFields aufrufen. Auf diese Weise bekommen wir unseren Json-String den es nun noch zu konvertieren gilt.

        public ActionResult StartSuche(SuchFilter filter)
        {
            var personen = Request.Form["Personen"];
            filter.Personen = ConvertJsonToPersonen(personen);
           var ergebnisListe = this.personManager.Find(filter);
           this.View(„Suche“, ergebnisListe);
        }

In meinem Fall bekomme ich eigentlich eine Liste von Objekten. Daher deserialisiere ich den String mit dem JavaScriptSerializer zu einem object[]. Um nun aber auf die Eigenschaften des Objekts zugreifen zu können wird es nötig das dynamic Schlüsselwort zu verwenden.

private IEnumerable<Person> ConvertJsonToInhaltsstoffe(string jsonPersonen)
        {
            var serializer = new JavaScriptSerializer();
            var deserialisiertePersonen = (object[])serializer.DeserializeObject(jsonPersonen);
            var personen = new List<Person>();
            if (deserialisiertePersonen = null)
            {
                return personen;
            }
            foreach (dynamic obj in deserialisiertePersonen)
            {
                var person  = new Person
                {
                    Name = obj.Name,
                    Alter = obj.Alter
                };
		…
                personen.Add(person );
            }
            return personen;
        }

Nun haben wir alles zusammen um den Filter durch die zusätzlichen Daten zu erweitern und können die Suche starten als wäre nichts gewesen.

Diese Lösung hat einen Nachteil: Sie ist nicht wiederverwendbar. In meinem Fall war das aber nicht notwendig und hat sich als durchaus praktikabel heraus gestellt. Sollte jemand ein Problem feststellen, so würde ich mich über einen Kommentar freuen.