Определение формата ответа

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 29.10.2015

Если мы обратимся к контроллеру 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="И. Тургенев" },
        //......................................
    });
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850