Udostępnij za pośrednictwem


Wysyłanie danych formularza HTML w interfejsie API sieci Web ASP.NET: dane zakodowane w postaci

Część 1. Dane zakodowane w postaci

W tym artykule pokazano, jak publikować dane zakodowane w formacie formularza do kontrolera internetowego interfejsu API.

Omówienie formularzy HTML

Formularze HTML używają polecenia GET lub POST do wysyłania danych na serwer. Atrybut metody elementu formularza daje metodę HTTP:

<form action="api/values" method="post">

Domyślną metodą jest GET. Jeśli formularz używa polecenia GET, dane formularza są zakodowane w identyfikatorze URI jako ciąg zapytania. Jeśli formularz używa funkcji POST, dane formularza są umieszczane w treści żądania. W przypadku danych POSTed atrybut entype określa format treści żądania:

entype (typ entype) Opis
application/x-www-form-urlencoded Dane formularza są kodowane jako pary nazw/wartości, podobne do ciągu zapytania identyfikatora URI. Jest to domyślny format post.
multipart/form-data Dane formularza są kodowane jako komunikat MIME z wieloma częściami. Użyj tego formatu, jeśli przekazujesz plik do serwera.

Część 1 tego artykułu przedstawia format x-www-form-urlencoded. Część 2 opisuje wieloczęściowy miME.

Wysyłanie typów złożonych

Zazwyczaj można wysłać typ złożony składający się z wartości pobranych z kilku kontrolek formularza. Rozważmy następujący model reprezentujący aktualizację stanu:

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; }
    }
}

Oto kontroler internetowego interfejsu API, który akceptuje Update obiekt za pośrednictwem funkcji POST.

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

    }
}

Uwaga

Ten kontroler używa routingu opartego na akcjach, więc szablon trasy to "api/{controller}/{action}/{id}". Klient opublikuje dane w pliku "/api/updates/complex".

Teraz napiszmy formularz HTML, aby użytkownicy przesyłali aktualizację stanu.

<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>

Zwróć uwagę, że atrybut akcji w formularzu jest identyfikatorem URI naszej akcji kontrolera. Oto formularz z niektórymi wartościami wprowadzonymi w:

Zrzut ekranu przedstawiający formularz typu złożonego H T M L z polem Stan i polem Data wypełnionym wartościami.

Gdy użytkownik kliknie pozycję Prześlij, przeglądarka wyśle żądanie HTTP podobne do następującego:

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

Zwróć uwagę, że treść żądania zawiera dane formularza sformatowane jako pary nazwa/wartość. Internetowy interfejs API automatycznie konwertuje pary nazw/wartości na wystąpienie Update klasy.

Wysyłanie danych formularza za pośrednictwem AJAX

Gdy użytkownik przesyła formularz, przeglądarka przechodzi z dala od bieżącej strony i renderuje treść komunikatu odpowiedzi. Jest to ok, gdy odpowiedź jest stroną HTML. Jednak w przypadku internetowego interfejsu API treść odpowiedzi jest zwykle pusta lub zawiera dane ustrukturyzowane, takie jak JSON. W takim przypadku warto wysłać dane formularza przy użyciu żądania AJAX, aby strona mogła przetworzyć odpowiedź.

Poniższy kod pokazuje, jak publikować dane formularza przy użyciu zapytania jQuery.

<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>

Funkcja jQuery submit zastępuje akcję formularza nową funkcją. Spowoduje to zastąpienie domyślnego zachowania przycisku Prześlij. Funkcja serializuje dane formularza w pary nazw/wartości. Aby wysłać dane formularza do serwera, wywołaj metodę $.post().

Po zakończeniu .success() żądania program obsługi lub .error() wyświetli użytkownikowi odpowiedni komunikat.

Zrzut ekranu przedstawiający formularz typu złożonego H T M L z błędem hosta lokalnego wyświetlanym pogrubionym tekstem dla użytkownika.

Wysyłanie prostych typów

W poprzednich sekcjach wysłaliśmy typ złożony, który internetowy interfejs API deserializował do wystąpienia klasy modelu. Można również wysyłać proste typy, takie jak ciąg.

Uwaga

Przed wysłaniem prostego typu rozważ zamiast tego zawijanie wartości w typie złożonym. Zapewnia to korzyści związane z weryfikacją modelu po stronie serwera i ułatwia rozszerzenie modelu w razie potrzeby.

Podstawowe kroki wysyłania prostego typu są takie same, ale istnieją dwie subtelne różnice. Najpierw w kontrolerze należy ozdobić nazwę parametru atrybutem FromBody .

[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);
    }

Domyślnie internetowy interfejs API próbuje pobrać proste typy z identyfikatora URI żądania. Atrybut FromBody informuje internetowy interfejs API o odczytaniu wartości z treści żądania.

Uwaga

Internetowy interfejs API odczytuje treść odpowiedzi co najwyżej raz, więc tylko jeden parametr akcji może pochodzić z treści żądania. Jeśli musisz uzyskać wiele wartości z treści żądania, zdefiniuj typ złożony.

Po drugie klient musi wysłać wartość w następującym formacie:

=value

W szczególności część nazwy pary nazwa/wartość musi być pusta dla prostego typu. Nie wszystkie przeglądarki obsługują to dla formularzy HTML, ale ten format można utworzyć w skrycie w następujący sposób:

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

Oto przykładowy formularz:

<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>

Oto skrypt do przesłania wartości formularza. Jedyną różnicą z poprzedniego skryptu jest argument przekazany do funkcji post .

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

Możesz użyć tego samego podejścia, aby wysłać tablicę prostych typów:

$.post('api/updates/postlist', { "": ["update one", "update two", "update three"] });

Dodatkowe zasoby

Część 2. Przekazywanie plików i wieloczęściowa miME