Senden von HTML-Formulardaten in ASP.NET-Web-API: Formular-urlencodierte Daten
Teil 1: Formular-URLencodierte Daten
In diesem Artikel erfahren Sie, wie Sie formular-urlencodierte Daten an einen Web-API-Controller senden.
- Übersicht über HTML-Formulare
- Senden komplexer Typen
- Senden von Formulardaten über AJAX
- Senden einfacher Typen
Übersicht über HTML-Formulare
HTML-Formulare verwenden entweder GET oder POST, um Daten an den Server zu senden. Das Method-Attribut des formular-Elements ergibt die HTTP-Methode:
<form action="api/values" method="post">
Die Standardmethode ist GET. Wenn das Formular GET verwendet, werden die Formulardaten im URI als Abfragezeichenfolge codiert. Wenn das Formular POST verwendet, werden die Formulardaten im Anforderungstext platziert. Für POSTed-Daten gibt das enctype-Attribut das Format des Anforderungstexts an:
Enctype | BESCHREIBUNG |
---|---|
application/x-www-form-urlencoded | Formulardaten werden als Name-Wert-Paare codiert, ähnlich wie eine URI-Abfragezeichenfolge. Dies ist das Standardformat für POST. |
multipart/form-data | Formulardaten werden als mehrteilige MIME-Nachricht codiert. Verwenden Sie dieses Format, wenn Sie eine Datei auf den Server hochladen. |
Teil 1 dieses Artikels befasst sich mit dem x-www-form-urlencoded-Format. Teil 2 beschreibt mehrteiliges MIME.
Senden komplexer Typen
In der Regel senden Sie einen komplexen Typ, der aus Werten aus mehreren Formularsteuerelementen besteht. Betrachten Sie das folgende Modell, das ein status Update darstellt:
namespace FormEncode.Models
{
using System;
using System.ComponentModel.DataAnnotations;
public class Update
{
[Required]
[MaxLength(140)]
public string Status { get; set; }
public DateTime Date { get; set; }
}
}
Hier sehen Sie einen Web-API-Controller, der ein Update
Objekt über POST akzeptiert.
namespace FormEncode.Controllers
{
using FormEncode.Models;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
public class UpdatesController : ApiController
{
static readonly Dictionary<Guid, Update> updates = new Dictionary<Guid, Update>();
[HttpPost]
[ActionName("Complex")]
public HttpResponseMessage PostComplex(Update update)
{
if (ModelState.IsValid && update != null)
{
// Convert any HTML markup in the status text.
update.Status = HttpUtility.HtmlEncode(update.Status);
// Assign a new ID.
var id = Guid.NewGuid();
updates[id] = update;
// Create a 201 response.
var response = new HttpResponseMessage(HttpStatusCode.Created)
{
Content = new StringContent(update.Status)
};
response.Headers.Location =
new Uri(Url.Link("DefaultApi", new { action = "status", id = id }));
return response;
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
[HttpGet]
public Update Status(Guid id)
{
Update update;
if (updates.TryGetValue(id, out update))
{
return update;
}
else
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
}
}
Hinweis
Dieser Controller verwendet aktionsbasiertes Routing, sodass die Routenvorlage "api/{controller}/{action}/{id}" lautet. Der Client postiert die Daten an "/api/updates/complex".
Nun schreiben wir ein HTML-Formular für Benutzer, um ein status Update zu übermitteln.
<h1>Complex Type</h1>
<form id="form1" method="post" action="api/updates/complex"
enctype="application/x-www-form-urlencoded">
<div>
<label for="status">Status</label>
</div>
<div>
<input name="status" type="text" />
</div>
<div>
<label for="date">Date</label>
</div>
<div>
<input name="date" type="text" />
</div>
<div>
<input type="submit" value="Submit" />
</div>
</form>
Beachten Sie, dass das Aktionsattribute im Formular der URI unserer Controlleraktion ist. Hier sehen Sie das Formular mit einigen Eingegebenen Werten:
Wenn der Benutzer auf Senden klickt, sendet der Browser eine HTTP-Anforderung ähnlich der folgenden:
POST http://localhost:38899/api/updates/complex HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Content-Type: application/x-www-form-urlencoded
Content-Length: 47
status=Shopping+at+the+mall.&date=6%2F15%2F2012
Beachten Sie, dass der Anforderungstext die Formulardaten enthält, die als Name/Wert-Paare formatiert sind. Die Web-API konvertiert die Namen-Wert-Paare automatisch in eine instance der Update
Klasse.
Senden von Formulardaten über AJAX
Wenn ein Benutzer ein Formular sendet, navigiert der Browser von der aktuellen Seite weg und rendert den Text der Antwortnachricht. Das ist in Ordnung, wenn es sich bei der Antwort um eine HTML-Seite handelt. Bei einer Web-API ist der Antworttext jedoch in der Regel leer oder enthält strukturierte Daten, z. B. JSON. In diesem Fall ist es sinnvoller, die Formulardaten mithilfe einer AJAX-Anforderung zu senden, damit die Seite die Antwort verarbeiten kann.
Der folgende Code zeigt, wie Formulardaten mithilfe von jQuery gepostt werden.
<script type="text/javascript">
$("#form1").submit(function () {
var jqxhr = $.post('api/updates/complex', $('#form1').serialize())
.success(function () {
var loc = jqxhr.getResponseHeader('Location');
var a = $('<a/>', { href: loc, text: loc });
$('#message').html(a);
})
.error(function () {
$('#message').html("Error posting the update.");
});
return false;
});
</script>
Die jQuery-Übermittlungsfunktion ersetzt die Formularaktion durch eine neue Funktion. Dadurch wird das Standardverhalten der Schaltfläche "Senden" außer Kraft gesetzt. Die Serialisierungsfunktion serialisiert die Formulardaten in Name/Wert-Paare. Um die Formulardaten an den Server zu senden, rufen Sie auf $.post()
.
Wenn die Anforderung abgeschlossen ist, zeigt der .success()
-Handler oder .error()
dem Benutzer eine entsprechende Nachricht an.
Senden einfacher Typen
In den vorherigen Abschnitten haben wir einen komplexen Typ gesendet, der von der Web-API an eine instance einer Modellklasse deserialisiert wurde. Sie können auch einfache Typen senden, z. B. eine Zeichenfolge.
Hinweis
Bevor Sie einen einfachen Typ senden, sollten Sie stattdessen den Wert in einen komplexen Typ umschließen. Dies bietet Ihnen die Vorteile der Modellvalidierung auf der Serverseite und vereinfacht die Erweiterung Ihres Modells bei Bedarf.
Die grundlegenden Schritte zum Senden eines einfachen Typs sind identisch, es gibt jedoch zwei subtile Unterschiede. Zunächst müssen Sie im Controller den Parameternamen mit dem FromBody-Attribut versehen.
[HttpPost]
[ActionName("Simple")]
public HttpResponseMessage PostSimple([FromBody] string value)
{
if (value != null)
{
Update update = new Update()
{
Status = HttpUtility.HtmlEncode(value),
Date = DateTime.UtcNow
};
var id = Guid.NewGuid();
updates[id] = update;
var response = new HttpResponseMessage(HttpStatusCode.Created)
{
Content = new StringContent(update.Status)
};
response.Headers.Location =
new Uri(Url.Link("DefaultApi", new { action = "status", id = id }));
return response;
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
Standardmäßig versucht die Web-API, einfache Typen aus dem Anforderungs-URI abzurufen. Das FromBody-Attribut weist die Web-API an, den Wert aus dem Anforderungstext zu lesen.
Hinweis
Die Web-API liest den Antworttext höchstens einmal, sodass nur ein Parameter einer Aktion aus dem Anforderungstext stammen kann. Wenn Sie mehrere Werte aus dem Anforderungstext abrufen müssen, definieren Sie einen komplexen Typ.
Zweitens muss der Client den Wert im folgenden Format senden:
=value
Insbesondere muss der Namensteil des Namenspaars für einen einfachen Typ leer sein. Nicht alle Browser unterstützen dies für HTML-Formulare, aber Sie erstellen dieses Format wie folgt im Skript:
$.post('api/updates/simple', { "": $('#status1').val() });
Hier sehen Sie ein Beispielformular:
<h1>Simple Type</h1>
<form id="form2">
<div>
<label for="status">Status</label>
</div>
<div>
<input id="status1" type="text" />
</div>
<div>
<input type="submit" value="Submit" />
</div>
</form>
Und hier ist das Skript zum Übermitteln des Formularwerts. Der einzige Unterschied zum vorherigen Skript ist das An die post-Funktion übergebene Argument.
$('#form2').submit(function () {
var jqxhr = $.post('api/updates/simple', { "": $('#status1').val() })
.success(function () {
var loc = jqxhr.getResponseHeader('Location');
var a = $('<a/>', { href: loc, text: loc });
$('#message').html(a);
})
.error(function () {
$('#message').html("Error posting the update.");
});
return false;
});
Sie können denselben Ansatz verwenden, um ein Array einfacher Typen zu senden:
$.post('api/updates/postlist', { "": ["update one", "update two", "update three"] });