Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Den här artikeln beskriver hur ASP.NET webb-API implementerar innehållsförhandling för ASP.NET 4.x.
HTTP-specifikationen (RFC 2616) definierar innehållsförhandling som "processen att välja den bästa representationen för ett givet svar när det finns flera tillgängliga representationer". Den primära mekanismen för innehållsförhandling i HTTP är följande begärandehuvuden:
- Acceptera: Vilka medietyper som är acceptabla för svaret, till exempel "application/json", "application/xml" eller en anpassad medietyp som "application/vnd.example+xml"
- Accept-Charset: Vilka teckenuppsättningar är godtagbara, till exempel UTF-8 eller ISO 8859-1.
- Accept-Encoding: Vilka innehållskodningar som är acceptabla, till exempel gzip.
- Accept-Language: Det föredragna naturliga språket, till exempel "en-us".
Servern kan också titta på andra delar av HTTP-begäran. Om en begäran till exempel innehåller ett X-Requested-With-huvudfält, som indikerar en AJAX-begäran, kan servern som standard returnera JSON om det inte finns något Accept-huvudfält.
I den här artikeln ska vi titta på hur webb-API:et använder rubrikerna Acceptera och Accept-Charset. (För närvarande finns det inget inbyggt stöd för Accept-Encoding eller Accept-Language.)
Serialisering
Om en webb-API-kontrollant returnerar en resurs som CLR-typ serialiserar pipelinen returvärdet och skriver det i HTTP-svarstexten.
Tänk till exempel på följande kontrollantåtgärd:
public Product GetProduct(int id)
{
var item = _products.FirstOrDefault(p => p.ID == id);
if (item == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return item;
}
En klient kan skicka denna HTTP-begäran:
GET http://localhost.:21069/api/products/1 HTTP/1.1
Host: localhost.:21069
Accept: application/json, text/javascript, */*; q=0.01
Som svar kan servern skicka:
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}
I det här exemplet begärde klienten antingen JSON, Javascript eller "anything" (*/*). Servern svarade med en JSON-representation av Product objektet. Observera att rubriken Innehållstyp i svaret är inställd på "application/json".
En kontrollant kan också returnera ett HttpResponseMessage-objekt . Om du vill ange ett CLR-objekt för svarstexten anropar du metoden CreateResponse-tillägg :
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);
}
Det här alternativet ger dig mer kontroll över informationen om svaret. Du kan ange statuskoden, lägga till HTTP-huvuden och så vidare.
Objektet som serialiserar resursen kallas för medieformaterare. Medieformaterare härleds från klassen MediaTypeFormatter . Webb-API:et tillhandahåller medieformaterare för XML och JSON, och du kan skapa anpassade formatters för att stödja andra medietyper. Information om hur du skriver en anpassad formatering finns i Media Formatters.
Så här fungerar innehållsförhandling
Först hämtar pipelinen IContentNegotiator-tjänsten från HttpConfiguration-objektet . Den hämtar också listan över medieformaterare från samlingen HttpConfiguration.Formatters .
Därefter anropar pipelinen IContentNegotiator.Negotiate och skickar in:
- Typ av objekt som ska serialiseras
- Samlingen med medieformaterare
- HTTP-begäran
Metoden Negotiate returnerar två informationsdelar:
- Vilken formaterare som ska användas
- Medietypen för svaret
Om ingen formatering hittas returnerar metoden Negotiatenull och klienten får HTTP-fel 406 (inte acceptabelt).
Följande kod visar hur en kontrollant direkt kan anropa innehållsförhandling:
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
)
};
}
Den här koden motsvarar vad pipelinen gör automatiskt.
Standardinnehållsförhandlare
Klassen DefaultContentNegotiator tillhandahåller standardimplementeringen av IContentNegotiator. Den använder flera kriterier för att välja en formaterare.
Först måste formateren kunna serialisera typen. Detta verifieras genom att anropa MediaTypeFormatter.CanWriteType.
Därefter tittar innehållsförhandlaren på varje formatering och utvärderar hur väl den matchar HTTP-begäran. För att utvärdera matchningen tittar innehållsförhandlaren på två saker på formateraren.
- Samlingen SupportedMediaTypes , som innehåller en lista över medietyper som stöds. Innehållsförhandlaren försöker matcha den här listan mot Accept-headern i begäran. Observera att sidhuvudet Acceptera kan innehålla intervall. Till exempel motsvarar "text/plain" text/* eller */*.
- Samlingen MediaTypeMappings , som innehåller en lista över MediaTypeMapping-objekt . Klassen MediaTypeMapping är ett allmänt sätt att matcha HTTP-begäranden med medietyper. Den kan till exempel mappa ett anpassat HTTP-huvud till en viss medietyp.
Om det finns flera matchningar vinner matchningen med den högsta kvalitetsfaktorn. Som exempel:
Accept: application/json, application/xml; q=0.9, */*; q=0.1
I det här exemplet har application/json en underförstådd kvalitetsfaktor på 1.0, så det föredras framför program/xml.
Om inga matchningar hittas försöker innehållsförhandlaren matcha medietypen för begäran, om det finns någon. Om begäran till exempel innehåller JSON-data letar innehållsförhandlaren efter en JSON-formaterare.
Om det fortfarande inte finns några matchningar väljer innehållsförhandlaren helt enkelt den första formaterare som kan serialisera typen.
Välja en teckenkodning
När en formatering har valts väljer innehållsförhandlaren den bästa teckenkodningen genom att titta på egenskapen SupportedEncodings i formateraren och matcha den mot Accept-Charset-huvudet i begäran (om någon).