Invio di dati del modulo HTML in API Web ASP.NET: dati form-urlencoded
Parte 1: Dati form-urlencoded
Questo articolo illustra come pubblicare dati form-urlencoded in un controller API Web.
- Panoramica dei moduli HTML
- Invio di tipi complessi
- Invio di dati del modulo tramite AJAX
- Invio di tipi semplici
Panoramica dei moduli HTML
I moduli HTML usano GET o POST per inviare dati al server. L'attributo del metodo dell'elemento modulo fornisce il metodo HTTP:
<form action="api/values" method="post">
Il metodo predefinito è GET. Se il modulo usa GET, i dati del modulo vengono codificati nell'URI come stringa di query. Se il modulo utilizza POST, i dati del modulo vengono inseriti nel corpo della richiesta. Per i dati POSTed, l'attributo enctype specifica il formato del corpo della richiesta:
enctype | Descrizione |
---|---|
application/x-www-form-urlencoded | I dati del modulo vengono codificati come coppie nome/valore, simili a una stringa di query URI. Questo è il formato predefinito per POST. |
multipart/form-data | I dati del modulo vengono codificati come messaggio MIME multipart. Usare questo formato se si carica un file nel server. |
La parte 1 di questo articolo esamina il formato x-www-form-urlencoded. La parte 2 descrive MIME multiparte.
Invio di tipi complessi
In genere, si invierà un tipo complesso, composto da valori acquisiti da diversi controlli modulo. Si consideri il modello seguente che rappresenta un aggiornamento dello stato:
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; }
}
}
Ecco un controller API Web che accetta un Update
oggetto tramite 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);
}
}
}
}
Nota
Questo controller usa il routing basato sulle azioni, quindi il modello di route è "api/{controller}/{action}/{id}". Il client pubblicherà i dati in "/api/updates/complex".
A questo punto si scriverà un modulo HTML per consentire agli utenti di inviare un aggiornamento dello stato.
<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>
Si noti che l'attributo action nel form è l'URI dell'azione del controller. Di seguito è riportato il modulo con alcuni valori immessi in:
Quando l'utente fa clic su Invia, il browser invia una richiesta HTTP simile alla seguente:
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
Si noti che il corpo della richiesta contiene i dati del modulo, formattati come coppie nome/valore. L'API Web converte automaticamente le coppie nome/valore in un'istanza della Update
classe .
Invio di dati del modulo tramite AJAX
Quando un utente invia un modulo, il browser si allontana dalla pagina corrente ed esegue il rendering del corpo del messaggio di risposta. Ok quando la risposta è una pagina HTML. Con un'API Web, tuttavia, il corpo della risposta è in genere vuoto o contiene dati strutturati, ad esempio JSON. In tal caso, è più opportuno inviare i dati del modulo usando una richiesta AJAX, in modo che la pagina possa elaborare la risposta.
Il codice seguente illustra come pubblicare i dati del modulo 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>
La funzione di invio di jQuery sostituisce l'azione form con una nuova funzione. In questo modo viene eseguito l'override del comportamento predefinito del pulsante Invia. La funzione serialize serializza i dati del modulo in coppie nome/valore. Per inviare i dati del modulo al server, chiamare $.post()
.
Al termine della richiesta, il .success()
gestore o .error()
visualizza un messaggio appropriato all'utente.
Invio di tipi semplici
Nelle sezioni precedenti è stato inviato un tipo complesso, che l'API Web ha deserializzato a un'istanza di una classe modello. È anche possibile inviare tipi semplici, ad esempio una stringa.
Nota
Prima di inviare un tipo semplice, è consigliabile eseguire il wrapping del valore in un tipo complesso. Ciò offre i vantaggi della convalida del modello sul lato server e semplifica l'estensione del modello, se necessario.
I passaggi di base per inviare un tipo semplice sono gli stessi, ma esistono due piccole differenze. Innanzitutto, nel controller è necessario decorare il nome del parametro con l'attributo 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);
}
Per impostazione predefinita, l'API Web tenta di ottenere tipi semplici dall'URI della richiesta. L'attributo FromBody indica all'API Web di leggere il valore dal corpo della richiesta.
Nota
L'API Web legge il corpo della risposta al massimo una volta, quindi solo un parametro di un'azione può provenire dal corpo della richiesta. Se è necessario ottenere più valori dal corpo della richiesta, definire un tipo complesso.
In secondo luogo, il client deve inviare il valore con il formato seguente:
=value
In particolare, la parte del nome della coppia nome/valore deve essere vuota per un tipo semplice. Non tutti i browser supportano questa opzione per i moduli HTML, ma si crea questo formato nello script come indicato di seguito:
$.post('api/updates/simple', { "": $('#status1').val() });
Di seguito è riportato un esempio di modulo:
<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>
Ed ecco lo script per inviare il valore del modulo. L'unica differenza rispetto allo script precedente è l'argomento passato nella funzione 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;
});
È possibile usare lo stesso approccio per inviare una matrice di tipi semplici:
$.post('api/updates/postlist', { "": ["update one", "update two", "update three"] });