Freigeben über


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

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:

Screenshot des Formulars

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.

Screenshot des Formulars

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"] });

Zusätzliche Ressourcen

Teil 2: Dateiupload und mehrteiliger MIME