Compartilhar via


Enviando dados de formulário HTML em ASP.NET API Web: dados codificados por formulário

Parte 1: Dados de formulário codificados como urlencoded (application/x-www-form-urlencoded)

Este artigo mostra como postar dados de formulário codificados como URL em um controlador de API da Web.

Visão geral dos Formulários HTML

Formulários HTML usam GET ou POST para enviar dados para o servidor. O atributo de método do elemento form fornece o método HTTP:

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

O método padrão é GET. Se o formulário usar GET, os dados do formulário serão codificados no URI como uma cadeia de caracteres de consulta. Se o formulário usar POST, os dados do formulário serão colocados no corpo da solicitação. Para dados POSTed, o atributo enctype especifica o formato do corpo da solicitação:

Enctype Descrição
application/x-www-form-urlencoded Os dados do formulário são codificados como pares nome/valor, semelhantes a uma cadeia de caracteres de consulta URI. Esse é o formato padrão para POST.
multipart/form-data Os dados do formulário são codificados como uma mensagem MIME de várias partes. Use esse formato se você estiver carregando um arquivo no servidor.

A parte 1 deste artigo analisa o formato x-www-form-urlencoded. A parte 2 descreve MIME de várias partes.

Enviando tipos complexos

Normalmente, você enviará um tipo complexo, composto por valores obtidos de vários controles de formulário. Considere o seguinte modelo que representa uma atualização de status:

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

Aqui está um controlador de API Web que aceita um Update objeto via 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);
            }
        }

    }
}

Observação

Esse controlador usa o roteamento baseado em ação, portanto, o modelo de rota é "api/{controller}/{action}/{id}". O cliente postará os dados em "/api/updates/complex".

Agora, vamos escrever um formulário HTML para que os usuários enviem uma atualização de status.

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

Observe que o atributo de ação no formulário é o URI da ação do controlador. Aqui está o formulário com alguns valores inseridos em:

Captura de tela do formulário H T M L do Tipo Complexo com um campo Status e um campo Data preenchido com valores.

Quando o usuário clica em Enviar, o navegador envia uma solicitação HTTP semelhante à seguinte:

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

Observe que o corpo da solicitação contém os dados do formulário, formatados como pares nome/valor. A API Web converte automaticamente os pares nome/valor em uma instância da Update classe.

Enviando dados de formulário por meio do AJAX

Quando um usuário envia um formulário, o navegador navega para longe da página atual e renderiza o corpo da mensagem de resposta. Tudo bem quando a resposta for uma página HTML. Com uma API Web, no entanto, o corpo da resposta geralmente está vazio ou contém dados estruturados, como JSON. Nesse caso, faz mais sentido enviar os dados do formulário usando uma solicitação AJAX, para que a página possa processar a resposta.

O código a seguir mostra como postar dados de formulário usando 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>

A função de envio jQuery substitui a ação de formulário por uma nova função. Isso substitui o comportamento padrão do botão Enviar. A função serializar serializa os dados do formulário em pares nome/valor. Para enviar os dados do formulário para o servidor, chame $.post().

Quando a solicitação for concluída, o manipulador .success() ou .error() exibirá uma mensagem adequada ao usuário.

Captura de tela do formulário H T M L do Tipo Complexo com um erro de host local exibido em texto em negrito para o usuário.

Enviando tipos simples

Nas seções anteriores, enviamos um tipo complexo, que a API Web desserializou para uma instância de uma classe de modelo. Você também pode enviar tipos simples, como uma cadeia de caracteres.

Observação

Antes de enviar um tipo simples, considere encapsular o valor em um tipo complexo. Isso oferece os benefícios da validação de modelo no lado do servidor e facilita a extensão do modelo, se necessário.

As etapas básicas para enviar um tipo simples são as mesmas, mas há duas diferenças sutis. Primeiro, no controlador, você deve decorar o nome do parâmetro com o atributo 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);
    }

Por padrão, a API Web tenta obter tipos simples do URI de solicitação. O atributo FromBody instrui a API Web a ler o valor do corpo da solicitação.

Observação

A API Web lê o corpo da resposta no máximo uma vez, portanto, apenas um parâmetro de uma ação pode vir do corpo da solicitação. Se você precisar obter vários valores do corpo da solicitação, defina um tipo complexo.

Em segundo lugar, o cliente precisa enviar o valor com o seguinte formato:

=value

Especificamente, para um tipo simples, a parte do nome do par nome/valor deve estar vazia. Nem todos os navegadores dão suporte a isso para formulários HTML, mas você cria esse formato no script da seguinte maneira:

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

Aqui está um exemplo de formulário:

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

E aqui está o script para enviar o valor do formulário. A única diferença do script anterior é o argumento passado para a função 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;
});

Você pode usar a mesma abordagem para enviar uma matriz de tipos simples:

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

Recursos adicionais

Parte 2: Upload de arquivo e MIME multipart