Archiv für den Monat April 2013

MVC Einführung/Tutorial in Custom Editor Templates inklusive der Einbindung von HTML5 Attributen im Model


Wenn ich bisher für meine Viewdaten eine extra CSS Klasse oder ein weiteres HTML5 Attribut benötigt habe, dann sah das z.B. folgendermaßen aus.

 @Html.TextBoxFor(model => model.CurrentDate, 
                new { @class = "input-small " + WebConstants.DatePickerCssClass, 
                           @Value = Model.CurrentDate.ToString(WebConstants.InputDateTimeFormat),
								type="date" })

Da kann man schnell den Überblick verlieren und außerdem gibt es noch ne Menge HTML5 Attribute die man anwenden kann. Es gibt aber noch eine weitere Möglichkeit das “Problem” anzugehen und die heißt “MVC Editor Templates”.

1. Ein paar Grundlagen zu den MVC Editor Templates

Sobald Ihr die Funktion “@HTML.EditorFor(….)” oder “@HTML.DisplayFor(…)” nutzt greift MVC auf Editor Templates zurück, wenn es keine Custom Templates findet, dann nimmt es seine eigenen die von MS vordefiniert wurden. Einen sehr guten Artikel darüber hat Brad Wilson geschrieben. MVC unterscheidet in “EditorTemplates” zum Bearbeiten von Werten und “DisplayTemplates” zum Anzeigen von Werten.

Die Eigenen Templates können entweder unter dem jeweiligen View abgelegt werden (im Ordner “DisplayTemplates” oder “EditorTemplates”) oder unter dem Shared Folder. MVC prüft dann erst den jeweiligen passenden View Folder, wenn Ihr spezielle Templates für einen View erstellt habt und wenn MVC dort keine findet, wird weiter im Shared Folder nach Templates geschaut.

imageimage

Standardmäßig gibt es für Alle Standarddatentypen wie “Datetime”, “Int32/64”, “String” und “Bool” ein Template. In MVC kann man aber bei den Modeldaten noch ein Attribut “DataType” festlegen und für jeden DataType gibt es ebenfalls noch ein Standardtemplate.

Bei der Verwendung des DataType Attributs ist außerdem zu beachten, das der verwendete DataType Vorrang vor dem Datentyp den Properties selbst hat. Im Folgenden Beispiel wird also nicht das Template “DateTime” verwendet, sondern es wird das Template “Time” aufgerufen.

Das DataType Attribut hat noch weitere Auswirkungen auf unsere Templates, denn das DataType Attribut legt z.B. fest wie der Ausgabewert “vorformatiert” wird. Wenn es sich z.B. um ein Datetime Attribut handelt mit dem DataType “Time” dann wird bei der Ausgabe nur noch die Zeit ausgegeben z.B. “13:34”, oder wenn für DataType “Date” steht, dann wir z.B. “23.04.2013” ausgegeben und beim DataType “DateTime” wird z.B. “23.04.2013 13:34” ausgegeben.

/// 
/// Verwendung des DataType Attributes Time, veranlasst MVC
/// nicht das "DateTime" Template zu nutzen
/// sondern, es wird das "Time" Template genommen.
/// 
[DataType(DataType.Time)]
[Display(Name = "Aktuelle Zeit")]
public DateTime CurrentTime { get; set; }

Wenn man also ein Element mit “EditorFor” erstellt, dann prüft MVC welcher Datentyp dargestellt werden soll und sucht ein passendes Template heraus und wenn es keines vom User findet, werden die eigenen von MVC benutzt.

Die Funktion “EditorFor” bietet aber auch die Möglichkeit zu sagen, welches Template verwendet werden soll, wenn man z.B. spezielle Custom Templates angelegt hat.

</pre>
<div class="control-group">@Html.LabelFor(model => model.Datum, new { @class = "control-label" })
<div class="controls">@* Aufruf des Standardtemplates für unser Datum. *@ @Html.EditorFor(model => model.Datum) @Html.ValidationMessageFor(model => model.Datum)</div>
</div>
<div class="control-group">@Html.LabelFor(model => model.Datum, new { @class = "control-label" })
<div class="controls">@* Aufruf des Custom Templates "Custom.Date" für unser Datum. *@ @Html.EditorFor(model => model.Datum, "Custom.Date") @Html.ValidationMessageFor(model => model.Datum)</div>
</div>
<pre>

Oder man kann bereits im Model festlegen welches Custom Template genutzt werden soll mittels des Attributs “UIHint”

[HtmlTag(Autofocus = true)]
[DataType(DataType.Date)]
[Display(Name = "Geburtstag")]
[UIHint("Custom.Date")]
public DateTime Geburtsdatum { get; set; }

Aber wie sieht ein Editor Template eigentlich aus? Dies kann sehr unterschiedlich sein, von sehr einfachen Varianten die nur eine zusätzliche CSS Klasse setzten, bis hin zu Templates die direkt DiplayValue und EditorValue anzeigen und in die passende Tagstruktur einbinden.

@* Text.cshtml *@
@model String

@* Einfaches Template was nur den Wert wieder in einer Textbox darstellt *@
@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "span4"})

Es ist auch möglich nicht “@Html.TextBox” zu nutzen und das komplette Control selbst zu “erstellen” als “input”, hier kommt es ganz darauf an was man machen will und wie viel Aufwand man aufwenden möchte. Auch das direkte Einbinden von JavaScript Code ist kein Problem.

@* Custom.Int32.cshtml *@
@model Int32

@* Im Template direkt eine bestimmte Formatierung angeben *@</pre>
<div class="control-group"><strong>Custom Int32 Template</strong> @Html.Encode(ViewData.ModelMetadata.DisplayName):
<div class="controls">@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue)</div>
</div>
<pre>

2. Einbinden von HTML5 Attributen mit Hilfe eines Attributes im Model

Ich bin häufig vom “EditorFor” gewechselt zu “TextBoxFor” um eigene HTML Attribute angeben zu können wie den Type oder um die Formatierung des Values bestimmen zu können (wie im Beispiel ganz zu beginn). Hier verliert man aber sehr schnell den Überblick wo man was im View gesetzt hat. Hier kann das Direkte Setzten der passenden HTML5 Attribute oder beliebiger anderer Attribute direkt im Model weiterhelfen.

Die Umsetzung, dazu ist letztendlich sehr einfach, denn man muss in seiner Attributklasse nur das Interface “IMetadataAware” einbinden und die dazu gehörende Methode “OnMetadataCreated(ModelMetadata metadata)” einbinden und schon werden von MVC die passenden Werte auch im Template zur Verfügung gestellt.

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class HtmlTagAttribute : Attribute, IMetadataAware
{
    /// 
    /// String der den Key für die "AdditionalValues" Collection enthält in der unsere Attributliste liegt.
    /// 
    public const string HtmlTagAdditionalValuesKey = "HtmlTagAdditionalValues";

    /// 
    /// Wird beim Erstellen der Metadaten für Unser Model aufgerufen und setzt in der passenden Collection
    /// unsere AttributCollection auf die wir dann in den Templates zugreifen können.
    ///  
    /// 
    public void OnMetadataCreated(ModelMetadata metadata)
    {
        //metadata.TemplateHint = "Strings";
        metadata.AdditionalValues[HtmlTagAdditionalValuesKey] = OptionalAttributes();
    }

    /// 
    /// Maximale Länge des Eingabefeldes
    /// 
    public int MaxLength { get; set; }

    /// 
    ///  The min and max attributes works with the following input 
    ///  EHtmlInputTypes: number, range, date, datetime, datetime-local, month, time and week.
    /// 
    public int Min { get; set; }

    /// 
    /// Gibt an ob ein MinValues angegeben wurde
    /// 
    public bool HasMinValues { get; set; }

    /// 
    ///  The min and max attributes works with the following input
    ///  EHtmlInputTypes: number, range, date, datetime, datetime-local, month, time and week.
    /// 
    public int Max { get; set; }

    /// 
    /// The pattern attribute works with the following input types: text, search, url, tel, email, and password.
    /// e.g.: pattern="[A-Za-z]{3}"
    /// 
    public string Pattern { get; set; }

    /// 
    /// The hint is displayed in the input field when it is empty, and disappears when the field gets focus.
    /// 
    public string Placeholder { get; set; }

    /// 
    /// Gibt an ob es sich nur um ein Readonly Feld handelt.
    /// 
    public bool ReadOnly { get; set; }

    /// 
    /// Gibt an ob das Feld Disabled sein soll
    /// 
    public bool Disabled { get; set; }

    /// 
    /// Specifies the shortcut key to activate/focus the element
    /// 
    public string AccessKey { get; set; }

    public int TabIndex { get; set; }
    public string CssClass { get; set; }

    /// 
    /// Gibt an ob auf das Element der Autofokus beim Pageload gesetzt werden soll
    /// Achtung sollte nur einmal Pro "seite" / "Model" verwendet werden.
    /// 
    public bool Autofocus { get; set; }

    /// 
    /// Der Jeweilige Inputtype, hier muss selbst darauf geachtet
    /// werden das dieser nicht mit dem .NET Inputtype "kollidiert"
    ///  und zusammenpasst. - HtmlInputTypes Klasse enthält alle gängigen Input Types
    /// 
    public string InputType { get; set; }

    /// 
    /// Erstellt aus den jeweils gesetzten Attributen eine Liste aus Attributname und Value.
    /// 
    /// 
    public Dictionary OptionalAttributes()
    {
        var options = new Dictionary();

        if (MaxLength != 0)
        {
            options.Add("maxlength", MaxLength);
        }

        if (ReadOnly)
        {
            options.Add("readonly", "readonly");
        }

        if (Disabled)
        {
            options.Add("disabled", "disabled");
        }

        if (Autofocus)
        {
            options.Add("autofocus", null);
        }

        if (!string.IsNullOrWhiteSpace(AccessKey))
        {
            options.Add("accessKey", AccessKey);
        }

        if (TabIndex != 0)
        {
            options.Add("tabindex", TabIndex);
        }

        if (!string.IsNullOrWhiteSpace(CssClass))
        {
            options.Add("class", CssClass);
        }

        if (!string.IsNullOrWhiteSpace(InputType))
        {
            //Der Name des Enums entspricht dem Type direkt.
            options.Add("type", InputType);
        }

        if (HasMinValues)
        {
            options.Add("min", Min);
        }

        if (Max > 0)
        {
            options.Add("max", Max);
        }

        if (!string.IsNullOrEmpty(Pattern))
        {
            options.Add("pattern", Pattern);
        }

        if (!string.IsNullOrEmpty(Placeholder))
        {
            options.Add("placeholder", Placeholder);
        }

        return options;
    }
}

Da wir die Werte die wir als Attribute in unser HTML Element aufnehmen wollen als KeyValuePair<string,object> Collection benötigen, gibt es in unserer Attributklasse die Funktion “OptionalAttributes()” die aus unseren Gesetzten Werten die passende Collection baut.

/// 
/// Die Input Types die wir zur Verfügung stellen.
/// 
public static class HtmlInputTypes
{
    public const string Text = "text";
    public const string Password = "password";
    public const string Datetime = "datetime";
    public const string Date = "date";
    public const string Month = "month";
    public const string Time = "time";
    public const string Week = "week";
    public const string Number = "number";
    public const string Range = "range";
    public const string Email = "email";
    public const string Url = "url";
    public const string Tel = "tel";
};

Verwendet werden kann das ganze dann z.B. folgendermaßen in unserem Model. Es muss nur auf die Verwendung des Properties “InputType” unseres Attributs aufgepasst werden, oder eine entsprechende Logik in den jeweiligen Controls eingebunden werden.

[HtmlTag(Autofocus = true, InputType = HtmlInputTypes.Time)]
[DataType(DataType.Time)]
[Display(Name = "Geburtszeit")]
public DateTime BirthTime { get; set; }

[HtmlTag(MaxLength = 5, Min=10, Max=50000, CssClass = "input-xxlarge")]
[Display(Name = "Geld in Euro")]
public int Geld { get; set; }

Und umgesetzt wird das ganze dann entsprechend in jedem Template wo die Attribute gesetzt werden sollen. Wir können auch im Template noch bestimmte Werte für das jeweilige Template automatisch setzten lassen oder neue hinzufügen.

@model DateTime
@using Mvc4WebApiKoTb.Helpers.MvcBasic

@{
    var values = new Dictionary();
    if (ViewData.ModelMetadata.AdditionalValues.ContainsKey(HtmlTagAttribute.HtmlTagAdditionalValuesKey))
    {
        values = (Dictionary)ViewData.ModelMetadata.AdditionalValues[HtmlTagAttribute.HtmlTagAdditionalValuesKey];
    }
    
}

@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, values)
@* Custom.Date.cshtml *@
@model DateTime
@using Mvc4WebApiKoTb.Helpers.MvcBasic

@{
    var values = new Dictionary();
    if (ViewData.ModelMetadata.AdditionalValues.ContainsKey(HtmlTagAttribute.HtmlTagAdditionalValuesKey))
    {
        values = (Dictionary)ViewData.ModelMetadata.AdditionalValues[HtmlTagAttribute.HtmlTagAdditionalValuesKey];
    }

    var anzeige = string.Empty;
    if (ViewData.TemplateInfo.FormattedModelValue != null)
    {
        DateTime datum = (DateTime) ViewData.TemplateInfo.FormattedModelValue;
        //Hier wird das übergebene Datum direkt Formatiert ausgegeben
        anzeige = datum.ToString("dd.MM.yyyy");
    }
}

<strong>Custom Date Value</strong> 
@Html.TextBox("", anzeige, values)

Damit haben wir ein eigenes Template für DateTime, welches automatisch die passenden Attribute unserem HTML Element hinzufügt oder sogar das Datum selbst formatiert.

3. Quellen und Code auf Codeplex

http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-4-custom-object-templates.html
http://stackoverflow.com/questions/7313284/how-can-editor-templates-display-templates-recognize-any-attributes-assigned-t
http://www.dotnetcurry.com/ShowArticle.aspx?ID=687

Codeplex:

Dann unter “Source Code” –> “Browse” –> “Testprojekte” –> “Mvc4WebApiKoTb” hier findet Ihr dann die Wichtigsten Dateien im Webprojekt unter “Views/Testtemplate”, “Models/Testtemplates” und “Helpers/MvcBasic”. Das Projekt sollte auch so lauffähig sein.

MVC Multiple Submitbuttons “verarbeiten” / “auswerten”


Oft geht es schneller als man “Multiple Submitbuttons” aussprechen kann und da steht man vor dem “Problem”, das man mehrere Submit Buttons in seinem Formular untergebracht hat. Spätestens dann fragt man sich, wie bekomme ich heraus welcher Button geklickt wurde.

Hier findet man im Netzt die unterschiedlichsten Herangehensweisen. Ich werde hier auf zwei einfache Varianten eingehen, die beim Submit immer die gleiche Controllermethode aufrufen und diese entscheidet dann was zu tun ist.

Die HTML Button Tags für Nummer eins schauen folgendermaßen aus

<button type="submit" class="btn" name="BtnIdPrevDay"><i class="icon-chevron-left"></i></button>
<button type="submit" class="btn" name="BtnIdNextDay"><i class="icon-chevron-right"></i></button>

Hier wurde zur Anzeige ein Symbol/Icon (Twitter Bootstrap) verwenden und kein Text. Wir ermitteln welcher Button geklickt wurde, anhand des Buttonnamen der angegeben wurde, d.h. aber auch das wir jedem Button in unserem Formular einen eindeutigen Namen geben müssen. Dann kann man im Controller überprüfen welcher Button geklickt wurde über die folgende Funktion. Das Model oder die Controlermethode muss für diese Methode auch nicht extra erweitert werden.

[HttpPost]
public ActionResult Worktime(CreateWorktimeEntryModel model)
{
    if (ModelState.IsValid)
    {
        if (Controller.HttpContext.Request.Form.AllKeys.Contains("BtnIdNextDay"))
        {
           //Do some Stuff for this Button
        }
        else if (Controller.HttpContext.Request.Form.AllKeys.Contains("BtnIdPrevDay"))
        {
	        //Do some Other Stuff other button was Clicked          
        }
    }
    return View(model);
}

Das HTML Konstrukt für Nummer zwei schaut folgendermaßen aus

 <button type="submit" class="btn" name="SubmitType" value="Erstellen mit Pause">Erstellen mit Pause</button>
 <button type="submit" class="btn" name="SubmitType" value="Erstellen ohne Pause">Erstellen ohne Pause</button>

Für Variante zwei muss das Model oder die Controllermethode für den Postback entsprechend angepasst werden. Denn bei Methode zwei greifen wir auf MVC Funktionalitäten zurück, die automatisch Werte aus dem Postback Methodenparametern oder Modelproperties zuweisen.

Der erste Lösungsweg sieht eine Erweiterung der Controllermethode für den Postback vor. Diese wird um den string Parameter mit dem Namen “SubtmitType” erweitert. Wenn jetzt ein Button geklickt wird, bei dem als Name “SubmitType” eingetragen ist, steht im Variablennamen der value z.B. “Erstellen mit Pause” und man kann im Controller entscheiden was gemacht werden soll.

[HttpPost]
public ActionResult Worktime(CreateWorktimeEntryModel model, string SubmitType)
{
    if (ModelState.IsValid)
    {
        if (SubmitType == "Erstellen mit Pause")
        {
           //Do some Stuff for this Button
        }
        else if (SubmitType == "Erstellen ohne Pause")
        {
	        //Do some Other Stuff other button was Clicked          
        }
    }
    return View(model);
}

Der zweite Lösungsweg sieht eine Erweiterung des Models vor. Im Model muss ein string Property mit dem Namen “SubmitType” angelegt werden. Bei einem Postback steht dann im Model in unserem Neuen Property welcher Button “value” das Postback ausgelöst hat. Dann können wir wie vorher entscheiden welche Funktion ausgelöst werden soll.

[HttpPost]
public ActionResult Worktime(CreateWorktimeEntryModel model)
{
    if (ModelState.IsValid)
    {
        if (model.SubmitType == "Erstellen mit Pause")
        {
           //Do some Stuff for this Button
        }
        else if (model.SubmitType == "Erstellen ohne Pause")
        {
	        //Do some Other Stuff other button was Clicked          
        }
    }
    return View(model);
}

Update: Eine weitere noch einfachere Lösung sieht folgendermaßen aus:

<button type="submit" name="submitAction" value="option1">click me 1</button>
<button type="submit" name="submitAction" value="option2">click me 2</button>

Hier wird der gleiche Name für alle Buttons hinterlegt und beim Klicken wird der hinterlegte Value dann an unsere Action im Controller übergeben wo wir dann anhand des Values entscheiden was wir ausführen wollen.

public ActionResult MyAction(string submitAction, MyModel model)
{
  ....
}

Quelle:

http://forums.asp.net/p/2000724/5749339.aspx?Re+MVC+with+multiple+submit+buttons

MVC WebAPI und Serialisieren von Eingabedaten ohne Form Submit


Die Tage hatte ich das Problem, dass ich auf einer Seite noch ein paar Eingabefelder für einen Filter unterbringen musste. Es war mir leider nicht möglich ein zweites Form Tag dafür zu erstellen, daher habe ich die Elemente mit in das Hauptformular übernommen.

Ich benötigte für meinen Ajax Request an die WebAPI aber nur die Eingabefelder für meinen Filter und nicht die gesamten Formulardaten und ich wollte auch nicht jedes Eingabefeld einzeln heraussuchen und die Werte per Hand zusammensetzten.

Wenn man dann weiß das man mit jQuery problemlos Formulare Serialisieren kann und man kurz im Internet sucht, findet man auch schnell eine Möglichkeit wie man nur bestimmte Eingabefelder serialisieren kann ohne dabei das ganze Formular zu nutzen. Ich habe einfach um meine Suchfelder ein DIV mit einer ID gesetzt und dann per jQuery und einem passenden Selector die passenden Daten erhalten.

<input id="currentDate" class="span35" type="date" name="currentDate">

<div id="searchDiv" class="well well-small">
  <div class="btn-block">
    <select id="FilterWorktimeTypeList" class="span42" name="FilterWorktimeTypeList">
   </div>
   <div class="input-append btn-block">
     <input id="filterText" class="span35" type="text" name="SearchText">
     <button id="filterBtn" class="btn" type="button">Filtern</button>
  </div>
</div>

Da currentDate nicht innerhalb unseres SuchDIVs liegt, müssen wir den Inhalt, danach per Hand zu unseren Daten hinzufügen. Wichtig ist, das jedes Eingabefeld einen Namen hat, denn sonst wird es nicht serialisieren. Außerdem kann nicht die Hausmethode von jQuery zum serialisieren verwendet werden, sondern die Funktion “serializeObject” muss verwendet werden und erst in Verbindung mit “JSON.stringify” wird unser Datenobjekt auch von der WebAPI “erkannt”.

//wir suchen alle Inputfelder unterhalb unseres Divs heraus.
var searchDiv = $("#searchDiv :input")
//Wir serealisieren erst unser "Formular" aka unser SuchDiv
var jsonData = searchDiv.serializeObject();
//Da im Suchdiv nicht unser Datum mit enthalten ist, fügen wir es unserem Objekt mit hinzu.
jsonData["Datum"] = $("#currentDate").val();
//Wir müssen unsere serealisieren Daten noch so umwandeln, das diese auch von der WebAPI erkannt werden
jsonData = JSON.stringify(jsonData);

Die Funktion “serializeObject” habe ich im Netz gefunden und funktioniert wunderbar. Die Funktion selbst greift auf die jQuery Funktion “serializeArray” zurück. Diese Standardfunktion reicht leider nicht aus um ein gültiges Objekt zu erstellen, was die WebAPI als Objekt erkennt und umwandelt.

//jQuery Plugin um z.B. direkt Inputfelder und derren Inhalt zu serealisieren als Objekt!
//http://stackoverflow.com/questions/1184624/convert-form-data-to-js-object-with-jquery
$.fn.serializeObject = function()
{
    var o = {};
    var a = this.serializeArray();
    $.each(a, function() {
        if (o[this.name] !== undefined) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
};

Damit die Daten dann auch entsprechend an die WebAPI als Model übergeben werden können benötigen wir ein passendes C# Model für die Daten.

public class WorktimeEntryFilterModel
{
  /// <summary>
  /// Der Text nach dem gesucht werden soll.
  /// </summary>
  public string SearchText { get; set; }

  /// <summary>
  /// Die ausgewählte ID der WorktimeTypeList für die Filter
  /// </summary>
  public int? FilterWorktimeTypeList { get; set; }

  /// <summary>
  /// Der Datumsstring aus dem Model.
  /// </summary>
  public string Datum { get; set; }
}

Wichtig ist, das ich bei meinen WebAPI Aufrufen eine extra Route eingebunden habe in der WebApiConfig, wieso und weshalb das könnt Ihr hier in einem anderen Artikel nachlesen.

Der Beispielhafte Aufruf unserer Daten “jsonData” kann dann z.B. folgendermaßen aussehen.

$.ajax({
   url: "/api/worktimeApi/ByTextFilter/@Model.UserId",
   type: "POST",
   data: jsonData
   contentType: 'application/json; charset=utf-8',
   statusCode: {
        200 /* OK */: function(daten) {
            //Do some fun with the Data
            }
   }
});

und die passende WepAPI Funktion die unsere Daten entgegennimmt und verarbeitet.

/// <summary>
/// Filtert den Eintrag nach den übergebenen Modeldaten
/// </summary>
/// <param name="id">Die UserId nach der gefiltert werden soll</param>
/// <param name="value">Unsere Modeldaten nach denen gefiltert werden soll</param>
public HttpResponseMessage ByTextFilter(long id, WorktimeEntryFilterModel value)
{
    if (value != null)
    {
        WorktimeListModel worktime = new WorktimeListModel(id, value);
        worktime.FilterWorktimeList();

        //Wird automatisch in JSON Objekt umgewandelt und gibt den StatusCode 200 für OK zurück!
        HttpResponseMessage response = Request.CreateResponse<WorktimeListModel>(HttpStatusCode.OK, worktime);
        response.Headers.Location = new Uri(Request.RequestUri, string.Format("/api/WorktimeApi/ByTextFilter/{0}", id.ToString()));
        return response;
    }

    throw new HttpResponseException(HttpStatusCode.BadRequest);
}

Damit ist es problemlos möglich nur kleine Teile eines großen Formulars zu benutzten. Vielleicht existiert auch kein Formular und damit hat man die Möglichkeit die Daten trotzdem problemlos zu serialisieren und zu versendet.