Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questo articolo descrive come ASP.NET'API Web implementa la negoziazione del contenuto per ASP.NET 4.x.
La specifica HTTP (RFC 2616) definisce la negoziazione del contenuto come "il processo di selezione della migliore rappresentazione per una determinata risposta quando sono disponibili più rappresentazioni". Il meccanismo principale per la negoziazione del contenuto in HTTP sono le intestazioni di richiesta seguenti:
- Accettare: Quali tipi di supporti sono accettabili per la risposta, ad esempio "application/json", "application/xml" o un tipo di supporto personalizzato, ad esempio "application/vnd.example+xml"
- Accept-Charset: Quali set di caratteri sono accettabili, ad esempio UTF-8 o ISO 8859-1.
- Accept-Encoding: Quali codifiche di contenuto sono accettabili, ad esempio gzip.
- Accept-Language: Linguaggio naturale preferito, ad esempio "en-us".
Il server può anche esaminare altre parti della richiesta HTTP. Ad esempio, se la richiesta contiene un'intestazione X-Requested-With, che indica una richiesta AJAX, il server potrebbe impostare come predefinito JSON se non è presente alcuna intestazione Accept.
In questo articolo verrà illustrato come l'API Web usa le intestazioni Accept e Accept-Charset. Attualmente non è disponibile alcun supporto predefinito per Accept-Encoding o Accept-Language.
Serializzazione
Se un controller API Web restituisce una risorsa come tipo CLR, la pipeline serializza il valore restituito e lo scrive nel corpo della risposta HTTP.
Si consideri ad esempio l'azione controller seguente:
public Product GetProduct(int id)
{
var item = _products.FirstOrDefault(p => p.ID == id);
if (item == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return item;
}
Un client potrebbe inviare questa richiesta HTTP:
GET http://localhost.:21069/api/products/1 HTTP/1.1
Host: localhost.:21069
Accept: application/json, text/javascript, */*; q=0.01
In risposta, il server potrebbe inviare:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 57
Connection: Close
{"Id":1,"Name":"Gizmo","Category":"Widgets","Price":1.99}
In questo esempio il client ha richiesto JSON, Javascript o "anything" (*/*). Il server ha risposto con una rappresentazione JSON dell'oggetto Product . Si noti che l'intestazione Content-Type nella risposta è impostata su "application/json".
Un controller può anche restituire un oggetto HttpResponseMessage . Per specificare un oggetto CLR per il corpo della risposta, chiamare il metodo di estensione CreateResponse :
public HttpResponseMessage GetProduct(int id)
{
var item = _products.FirstOrDefault(p => p.ID == id);
if (item == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return Request.CreateResponse(HttpStatusCode.OK, item);
}
Questa opzione offre un maggiore controllo sui dettagli della risposta. È possibile impostare il codice di stato, aggiungere intestazioni HTTP e così via.
L'oggetto che serializza la risorsa è denominato formattatore multimediale. I formattatori multimediali derivano dalla classe MediaTypeFormatter . L'API Web fornisce formattatori multimediali per XML e JSON ed è possibile creare formattatori personalizzati per supportare altri tipi di supporti. Per informazioni sulla scrittura di un formattatore personalizzato, vedere Formattatori multimediali.
Funzionamento della negoziazione del contenuto
Prima di tutto, la pipeline ottiene il servizio IContentNegotiator dall'oggetto HttpConfiguration . Ottiene anche l'elenco dei formattatori multimediali dall'insieme HttpConfiguration.Formatters .
Successivamente, la pipeline chiama IContentNegotiator.Negotiate, passando:
- Tipo di oggetto da serializzare
- Raccolta di formattatori multimediali
- Richiesta HTTP
Il metodo Negotiate restituisce due informazioni:
- Quale formattatore usare
- Tipo di media per la risposta
Se non viene trovato alcun formattatore, il metodo Negotiate restituisce null e il client riceve l'errore HTTP 406 (Non accettabile).
Il codice seguente illustra come un controller può richiamare direttamente la negoziazione del contenuto:
public HttpResponseMessage GetProduct(int id)
{
var product = new Product()
{ Id = id, Name = "Gizmo", Category = "Widgets", Price = 1.99M };
IContentNegotiator negotiator = this.Configuration.Services.GetContentNegotiator();
ContentNegotiationResult result = negotiator.Negotiate(
typeof(Product), this.Request, this.Configuration.Formatters);
if (result == null)
{
var response = new HttpResponseMessage(HttpStatusCode.NotAcceptable);
throw new HttpResponseException(response));
}
return new HttpResponseMessage()
{
Content = new ObjectContent<Product>(
product, // What we are serializing
result.Formatter, // The media formatter
result.MediaType.MediaType // The MIME type
)
};
}
Questo codice equivale a ciò che la pipeline esegue automaticamente.
Negoziazione di contenuti predefinito
La classe DefaultContentNegotiator fornisce l'implementazione predefinita di IContentNegotiator. Usa diversi criteri per selezionare un formattatore.
Innanzitutto, il formattatore deve poter serializzare il tipo. Questa operazione viene verificata chiamando MediaTypeFormatter.CanWriteType.
Successivamente, il negoziatore di contenuto esamina ogni formattatore e valuta il livello di corrispondenza con la richiesta HTTP. Per valutare la corrispondenza, il negoziatore di contenuto esamina due elementi nel formattatore:
- Raccolta SupportedMediaTypes , che contiene un elenco di tipi di supporti supportati. Il negoziatore dei contenuti tenta di confrontare questo elenco con l'intestazione 'Accept' della richiesta. Si noti che l'intestazione Accept può includere intervalli. Ad esempio, "text/plain" è una corrispondenza per text/* o */*.
- La raccolta MediaTypeMappings, che contiene un elenco di oggetti MediaTypeMapping. La classe MediaTypeMapping offre un modo generico per trovare una corrispondenza con le richieste HTTP con i tipi di supporti. Ad esempio, potrebbe eseguire il mapping di un'intestazione HTTP personalizzata a un particolare tipo di media.
Se ci sono più corrispondenze, vince quella con il fattore di qualità più alto. Per esempio:
Accept: application/json, application/xml; q=0.9, */*; q=0.1
In questo esempio application/json ha un fattore di qualità implicito pari a 1.0, quindi è preferibile rispetto a application/xml.
Se non vengono trovate corrispondenze, il negoziatore di contenuto tenta di abbinare il tipo di media del contenuto della richiesta, se presente. Ad esempio, se la richiesta contiene dati JSON, il negoziatore di contenuto cerca un formattatore JSON.
Se ancora non ci sono corrispondenze, il negoziatore di contenuti seleziona semplicemente il primo formattatore in grado di serializzare il tipo.
Selezione di una codifica di caratteri
Dopo aver selezionato un formattatore, il negoziatore di contenuto sceglie la codifica dei caratteri migliore esaminando la proprietà SupportedEncodings nel formattatore e associandola all'intestazione Accept-Charset nella richiesta (se presente).