Freigeben über


Senden von HTML-Formulardaten in ASP.NET Web-API: Formular-urlencodierte Daten

Teil 1: Form-urlencodierte Daten

In diesem Artikel wird gezeigt, wie Sie formular-urlencodierte Daten an einen Web-API-Controller senden.

Übersicht über HTML-Formulare

HTML-Formulare verwenden ENTWEDER GET oder POST, um Daten an den Server zu senden. Das Methodenattribute des Formularelements gibt die HTTP-Methode an:

<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 abgelegt. Für POSTed-Daten gibt das Attribut "enctype " 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.
Mehrteilige/Formulardaten 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

Normalerweise senden Sie einen komplexen Typ, der aus Werten besteht, die von mehreren Formularsteuerelementen stammen. Betrachten Sie das folgende Modell, das eine Statusaktualisierung 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 ist ein 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 sendet die Daten in "/api/updates/complex".

Jetzt schreiben wir ein HTML-Formular für Benutzer, um eine Statusaktualisierung zu senden.

<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 Aktions-Attribut im Formular der URI unserer Controlleraktion ist. Hier ist das Formular mit einigen eingegebenen Werten:

Screenshot des Formulars

Wenn der Benutzer auf "Absenden" klickt, sendet der Browser eine HTTP-Anforderung ähnlich wie folgt:

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 automatisch die Namen-Wert-Paare in eine Instanz der Update Klasse.

Senden von Formulardaten über AJAX

Wenn ein Benutzer ein Formular sendet, navigiert der Browser von der aktuellen Seite ab und rendert den Textkörper der Antwortnachricht. Das ist ok, wenn die Antwort eine HTML-Seite ist. 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 Submit-Funktion ersetzt die Formularaktion durch eine neue Funktion. Dadurch wird das Standardverhalten der Schaltfläche "Absenden" außer Kraft gesetzt. Die Serialisierungsfunktion serialisiert die Formulardaten in Name-Wert-Paare. Rufen Sie $.post()auf, um die Formulardaten an den Server zu senden.

Wenn die Anforderung abgeschlossen ist, zeigt der .success().error() Handler dem Benutzer eine entsprechende Meldung an.

Screenshot des Formulars

Senden einfacher Typen

In den vorherigen Abschnitten haben wir einen komplexen Typ gesendet, den die Web-API an eine Instanz einer Modellklasse deserialisiert hat. 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. Dadurch erhalten Sie die Vorteile der Modellüberprüfung auf serverseitiger Seite und können Ihr Modell bei Bedarf einfacher erweitern.

Die grundlegenden Schritte zum Senden eines einfachen Typs sind identisch, aber es gibt zwei subtile Unterschiede. Zuerst 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 mit dem folgenden Format senden:

=value

Insbesondere muss der Namensteil des Namens-Wert-Paares für einen einfachen Typ leer sein. Nicht alle Browser unterstützen dies für HTML-Formulare, aber Sie erstellen dieses Format in Skript wie folgt:

$.post('api/updates/simple', { "": $('#status1').val() });

Hier ist 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 Argument, das an die Postfunktion übergeben wird.

$('#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"] });

Zusätzliche Ressourcen

Teil 2: Dateiupload und mehrteiliges MIME