Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
Если мы обратимся к контроллеру Web API для получения некоторого списка объектов, например, по стандартному маршруту api/values/, то в IE мы получим эти объекты в формате json, а в Firefox и Chrome - в формате xml. Например, у нас есть следующий метод:
public List<Book> Get() { return new List<Book> { new Book {Id=1, Name="Война и мир", Author="Л. Толстой" }, new Book {Id=2, Name="Отцы и дети", Author="И. Тургенев" }, //................... }; }
В Firefox мы получим следующий результат:
<ArrayOfBook> <Book> <Author>Л. Толстой</Author> <Id>1</Id> <Name>Война и мир</Name> </Book> <Book> <Author>И. Тургенев</Author> <Id>2</Id> <Name>Отцы и дети</Name> </Book> </ArrayOfBook>
При взаимодействии с клиентом между ним и сервером происходят два процесса: content negotiation (согласование содержимого) и media formatting (форматирование или сериализация содержимого). На первом этапе сервер узнает, в каком формате клиенту предпочтительнее отправлять ответ. На втором этапе происходит сериализация данных в этот формат.
Данные о формате клиент передает
с помощью заголовка Accept. Различные браузеры отправляют разные заголовки Accept
. Например, в IE данный заголовок
выглядит следующим образом: Accept: text/html, application/xhtml+xml, */*
. Часть */*
указывает, что данные могут быть приняты
в любом формате. Поэтому IE получает в формате json - предпочтительном для Web API формате. Однако в других браузерах этот заголовок может выглядеть
другим образом, например, Accept: text/html, application/xhtml+xml, application/xml;q=0.9,*/*;q=0.8
. Здесь уже явно указывается с помощью
application/xml
, что браузер хочет получать данные в формате xml.
Web API имеет встроенную поддержку для следующих форматов: JSON, BSON, XML. Если же в запросе не передается заголовок Accept, то используется формат по умолчанию - json.
Однако мы можем явно указать приложению, чтобы оно посылало данные в формате json. Для этого в файл WebApiConfig.cs добавим строку:
using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; namespace TestWebApiApp { public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); // отключаем возможность вывода данных в формате xml config.Formatters.Remove(config.Formatters.XmlFormatter); } } }
Согласование формата на стороне сервера производит специальный класс, который представляет реализацию интерфейса IContentNegotiator.
public interface IContentNegotiator { ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters); }
Единственный метод интерфейса Negotiate
получает тип данных, данные запроса и набор форматировщиков MediaTypeFormatter, которые сериализуют данные
в ответ клиенту. А в качестве результата метода используется объект ContentNegotiationResult.
Если результат метода равен null
, то в ответ клиенту отправляется статусный код 406 (Unacceptable)
. Этот код указавает на невозможность
сериализации данных в нужный формат.
По умолчанию Web API уже содержит реализацию данного интерфейса по умолчанию - класс DefaultContentNegotiator. Но нам может потребоваться переопределить стандартное поведение данного класса. Например, нам надо отдавать клиенту с ОС Андроид данные в формате json. Для этого мы можем добавить в проект следующий класс:
using System; using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Formatting; using System.Net.Http.Headers; public class MyNegotiator : DefaultContentNegotiator { public override ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters) { if(request.Headers.UserAgent.ToString().ToLower().Contains("android")) { return new ContentNegotiationResult(new JsonMediaTypeFormatter(), new MediaTypeHeaderValue("application/json") ); } return base.Negotiate(type, request, formatters); } }
Тут мы проверяем, содержит ли строка UserAgent подстроку ""android", и если содержит, отдаем данные в формате json.
Но просто определить класс еще недостаточно. Теперь надо переопределить конфигурацию Web API. Для этого откроем файл WebApiConfig.cs, который находится в папке App_Start, и добавим в него одну строку:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Services.Replace(typeof(IContentNegotiator), new MyNegotiator()); // .........остальное содержимое файла } }
Метод config.Services.Replace()
заменяет стандартный тип DefaultContentNegotiator вышеопределенным классом для участия в согласовании содержимого.
И теперь на все браузеры под управлением ОС Андроид будет приходить контент в формате json.
Однако необязательно переопределять класс DefaultContentNegotiator, мы также можем воспользоваться стандартными методами:
Json(content)
: сериализует контент в json
Content(status, content, formatter)
: сериализует контент в определенный формат с помощью класса formatter
Content(status, content, formatter, mimeType)
: то же самое, только используется объект MediaTypeHeaderValue для определения mime-типа
Content(status, content, formatter, mimeString)
: аналогично предыдущему, только mime-тип определяется в виде строки
Эти методы переопределяют стандартный процесс согласования контента. Например, чтобы явным образом отправлять данные в формате json, используем метод Json():
public IHttpActionResult Get() { return Json(new List<Book> { new Book {Id=1, Name="Война и мир", Author="Л. Толстой" }, new Book {Id=2, Name="Отцы и дети", Author="И. Тургенев" }, //...................................... }); }