Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym artykule opisano, jak ASP.NET Web API implementuje negocjację zawartości dla ASP.NET 4.x.
Specyfikacja HTTP (RFC 2616) definiuje negocjacje zawartości jako "proces wybierania najlepszej reprezentacji dla danej odpowiedzi, gdy dostępnych jest wiele reprezentacji". Podstawowym mechanizmem negocjacji zawartości w protokole HTTP są następujące nagłówki żądań:
- Zaakceptować: Które typy multimediów są akceptowalne dla odpowiedzi, takie jak "application/json", "application/xml" lub niestandardowy typ nośnika, taki jak "application/vnd.example+xml"
- Accept-Charset: Które zestawy znaków są dopuszczalne, takie jak UTF-8 lub ISO 8859-1.
- Kodowanie akceptowania: Które kodowanie zawartości jest dopuszczalne, takie jak gzip.
- Accept-Language: Preferowany język naturalny, taki jak "en-us".
Serwer może również przyjrzeć się innym fragmentom żądania HTTP. Jeśli na przykład żądanie zawiera nagłówek X-Requested-With wskazujący żądanie AJAX, serwer może domyślnie używać formatu JSON, jeśli nie ma nagłówka Accept.
W tym artykule przyjrzymy się, jak internetowy interfejs API używa nagłówków Accept i Accept-Charset. (Obecnie nie ma wbudowanej obsługi Accept-Encoding lub Accept-Language).
Serializacja
Jeśli kontroler Web API zwraca zasób jako typ CLR, potok serializuje wartość zwracaną i zapisuje ją w treści odpowiedzi HTTP.
Rozważmy na przykład następującą akcję kontrolera:
public Product GetProduct(int id)
{
var item = _products.FirstOrDefault(p => p.ID == id);
if (item == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return item;
}
Klient może wysłać to żądanie HTTP:
GET http://localhost.:21069/api/products/1 HTTP/1.1
Host: localhost.:21069
Accept: application/json, text/javascript, */*; q=0.01
W odpowiedzi serwer może wysłać:
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}
W tym przykładzie klient zażądał formatu JSON, Języka Javascript lub "niczego" (*/*). Serwer odpowiedział reprezentacją Product obiektu w formacie JSON. Zwróć uwagę, że nagłówek Content-Type w odpowiedzi ma wartość "application/json".
Kontroler może również zwrócić obiekt HttpResponseMessage . Aby określić obiekt CLR dla treści odpowiedzi, wywołaj metodę rozszerzenia 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);
}
Ta opcja zapewnia większą kontrolę nad szczegółami odpowiedzi. Możesz ustawić kod stanu, dodać nagłówki HTTP itd.
Obiekt, który serializuje zasób, jest nazywany formaterem multimediów. Formatery multimediów pochodzą z klasy MediaTypeFormatter . Internetowy interfejs API udostępnia formatery multimediów dla formatu XML i JSON oraz można tworzyć niestandardowe formatery do obsługi innych typów multimediów. Aby uzyskać informacje na temat pisania niestandardowego programu formatującego, zobacz Media Formatters (Programy formatujące nośniki).
Jak działa negocjowanie zawartości
Najpierw potok pobiera usługę IContentNegotiator z obiektu HttpConfiguration. Pobiera również listę formaterów multimediów z kolekcji HttpConfiguration.Formatters .
Następnie potok wywołuje metodę IContentNegotiator.Negotiate, przekazując następujące elementy:
- Typ obiektu do serializacji
- Kolekcja formaterów multimediów
- Żądanie HTTP
Metoda Negotiate zwraca dwie informacje:
- Który formater ma być używany
- Typ nośnika odpowiedzi
Jeśli program formatujący nie zostanie znaleziony, metoda Negotiate zwraca wartość null, a klient otrzymuje błąd HTTP 406 (Nie do przyjęcia).
Poniższy kod pokazuje, jak kontroler może bezpośrednio wywoływać negocjacje zawartości:
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
)
};
}
Ten kod jest odpowiednikiem tego, co potok danych wykonuje automatycznie.
Domyślny negocjator treści
Klasa DefaultContentNegotiator udostępnia domyślną implementację interfejsu IContentNegotiator. Używa kilku kryteriów do wybrania formatatora.
Po pierwsze, program formatujący musi mieć możliwość serializacji typu. Jest to weryfikowane przez wywołanie metody MediaTypeFormatter.CanWriteType.
Następnie negocjator zawartości analizuje każdy formater i ocenia, jak dobrze pasuje do żądania HTTP. Aby ocenić dopasowanie, negocjator zawartości analizuje dwa elementy na formaterze:
- Kolekcja SupportedMediaTypes zawierająca listę obsługiwanych typów multimediów. Mechanizm uzgadniania zawartości próbuje dopasować tę listę do nagłówka żądania Accept. Należy pamiętać, że nagłówek Accept może zawierać zakresy. Na przykład "text/plain" dopasowuje się do tekst/* lub */*.
- Kolekcja MediaTypeMappings zawierająca listę obiektów MediaTypeMapping . Klasa MediaTypeMapping zapewnia ogólny sposób dopasowania żądań HTTP do typów multimediów. Na przykład może mapować niestandardowy nagłówek HTTP na określony typ nośnika.
Jeśli istnieje wiele meczów, mecz z najwyższą jakością wygrywa. Przykład:
Accept: application/json, application/xml; q=0.9, */*; q=0.1
W tym przykładzie plik application/json ma domniemany współczynnik jakości 1.0, więc preferowane jest użycie pliku application/xml.
Jeśli nie znaleziono dopasowań, negocjator zawartości próbuje dopasować typ nośnika treści żądania, jeśli istnieje. Jeśli na przykład żądanie zawiera dane JSON, negocjator zawartości szuka formattera JSON.
Jeśli nadal nie ma dopasowań, negocjator zawartości po prostu wybiera pierwszy formater, który może serializować dany typ.
Wybieranie kodowania znaków
Po wybraniu elementu formatującego negocjator zawartości wybiera najlepsze kodowanie znaków, sprawdzając właściwość SupportedEncodings w obiekcie formatującym i dopasowując je do nagłówka Accept-Charset w żądaniu (jeśli taki istnieje).