Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
Форматировщики медиа-типов отвечают за сериализацию данных для их отправки клиенту. WebApi имеет несколько встроенных форматировщиков.
Однако мы не ограничены только этими двумя типами и при желании может создать свой, заточенный под определенные нужды. Все форматировщики содержатся в коллекции HttpConfiguration.Formatters
.
Эта коллекция представляет объект MediaTypeFormatterCollection
и предоставляет прямой доступ к встроенным форматировщикам медиа-типов
с помощью следующих свойств:
FormUrlEncodedFormatter: возвращает объкт FormUrlEncodedMediaTypeFormatter
, который парсит
данные формы в процессе привязки модели
JsonFormatter: возвращает объект JsonMediaTypeFormatter
, который сериализует данные в формат JSON
XmlFormatter: возвращает объект XmlMediaTypeFormatter
, который сериализует данные в формат xml
Пространство имен System.Net.Http.Formatting
также включает еще один класс форматировщика - "BsonMediaTypeFormatter", который управляет
сериализацией в формат BSON. Однако в данный момент реализация поддержки спецификации BSON слабо реализована в клиентах. Поэтому по умолчанию данный
форматировщик отключен.
Создадим свой класс форматировщика ответа. Для этого определим в проекте для Web Api специальную папку Util, в которую добавим следующий класс BookFormatter:
using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Http; using System.Net.Http.Formatting; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; using WebApiApp.Models; namespace WebApiApp.Util { class BookFormatter : MediaTypeFormatter { public BookFormatter() { SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/x-books")); } public override bool CanReadType(Type type) { return type == typeof(Book) || type == typeof(IEnumerable<Book>); } public override bool CanWriteType(Type type) { return type == typeof(Book) || type == typeof(IEnumerable<Book>); } public override async Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext) { List<string> booksString = new List<string>(); IEnumerable<Book> books = value is Book ? new Book[] { (Book)value } : (IEnumerable<Book>)value; foreach (Book b in books) { booksString.Add(string.Format("{0},{1},{2}", b.Id, b.Name, b.Year)); } StreamWriter writer = new StreamWriter(writeStream); await writer.WriteAsync(string.Join(",", booksString)); writer.Flush(); } } }
Для создания форматировщика нам надо унаследовать класс от MediaTypeFormatter и переопределить ряд его методов.
В конструкторе форматировщика добавляется новый медиа-тип:
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/x-books"));
Форматировщик поддерживает коллекцию SupportedMediaTypes
, которая определяет набор mime-типов - объектов MediaTypeHeaderValue,
которые используются в заголовках при взаимодействии клиента и сервера. MIME-тип задается по принципу type/subtype
. Для личных mime-типов перед подтипом указывается префикс x.
Также переопределяем методы CanReadType и CanWriteType. Метод CanReadType
участвует в привязке моделей, а метод
CanWriteType
позволяет указать, может ли данный форматировщик сериализовать объект данного типа. Форматировщик будет отвечать за работу
с типом Book, поэтому он будет обрабатывать те данные, которые представляют либо единичный объект Book, либо коллекцию этих объектов.
Сама сериализация данных производится в асинхронном методе WriteToStreamAsync
, который принимает пять параметров:
type: тип сериализуемого объекта
value: сам объект для сериализации
writeStream: поток, в который будет сериализоваться ответ
content: объект, предоставляющий доступ к заголовкам ответа
transportContext: объект, предоставляющий информацию об используемом сетевом транспорте
Суть метода WriteToStreamAsync
- составление из значений отдельных свойств модели строки, в которой все эти значения разделены запятыми.
Данный способ сериализации очень примитивен и приводится только в целях демонстрации.
В конце список строк записывается в поток методом WriteAsync()
, при этом нам не надо закрывать поток.
После создания форматировщика его надо зарегистрировать в файле WebApiConfig.cs:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); // добавление форматировщика config.Formatters.Add(new BookFormatter()); } }
Добавление происходит в коллекцию форматировщиков Formatters, которая определена у объекта конфигурации HttpConfiguration.
На уровне контроллера нам менять ничего не надо, методы, как и раньше, отдают клиенту объекты:
public IEnumerable<Book> Get() { IEnumerable<Book> books = new List<Book> { new Book {Id=1, Name="Война и мир", Year=1863}, new Book {Id=2, Name="Отцы и дети", Year=1862}, new Book {Id=3, Name="Евгений Онегин", Year=1831}, }; return books; }
И теперь надо настроить получение данных в представлении:
<div id="tableBlock"></div> @section scripts { <script type="text/javascript"> $(document).ready(function () { GetAllBooks(); }); // Получение всех книг по ajax-запросу function GetAllBooks() { $.ajax({ url: '/api/values', type: 'GET', dataType: "text", accepts: { text: "application/x-books" }, success: function (data) { WriteResponse(data); } }); }; // вывод полученных данных на экран function WriteResponse(data) { var strResult = "<table><th>ID</th><th>Название</th><th>Год Издания</th>"; var arr = data.split(","); for (var i = 0; i < arr.length; i += 3) { strResult += "<tr><td>" + arr[i] + "</td><td> " + arr[i+1] + "</td><td>" + arr[i+2] + "</td></tr>"; } strResult += "</table>"; console.log(strResult); $("#tableBlock").html(strResult); } </script> }
Ключевым моментом здесь является установка типа данных и заголовка Accept с принимаемым MIME-типом:
dataType: "text", accepts: { text: "application/x-books" }
Настройка dataType
указывает, что данные ответа надо обрабатывать как текст, а параметр accepts
позволит обмениваться с сервером
данными в указанном MIME-типе.