Partilhar via


Enviando dados de formulário HTML em ASP.NET Web API: dados com código de formulário

Parte 1: Dados com urlencoded de formulário

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

Visão geral dos Formulários HTML

Os 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 o 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 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 por meio de 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 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 tipo complexo H T M L 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. No entanto, com uma API Web, 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 jQuery submit 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 .success() manipulador ou .error() exibirá uma mensagem apropriada para o usuário.

Captura de tela do formulário tipo complexo H T M L com um erro de host local exibido 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 do 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 informa à API Web para 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, a parte do nome do par nome/valor deve estar vazia para um tipo simples. 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 em relação ao 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 arquivos e MIME de várias partes