Поддержка BSON в веб-API ASP.NET 2.1

В этом разделе показано, как использовать BSON в контроллере веб-API (на стороне сервера) и в клиентском приложении .NET. В веб-API 2.1 реализована поддержка BSON.

Что такое BSON?

BSON — это двоичный формат сериализации. BSON означает двоичный JSON, но BSON и JSON сериализуются по-разному. BSON имеет тип JSON, так как объекты представлены в виде пар "имя-значение", аналогичных JSON. В отличие от JSON, числовые типы данных хранятся в виде байтов, а не строк.

Служба BSON была разработана так, чтобы она была легкой, легкой для сканирования и быстрой в кодировании и декодировании.

  • Размер BSON сравним с JSON. В зависимости от конкретных данных полезные данные BSON могут занять меньше или больше пространства, чем полезные данные JSON. Для сериализации двоичных данных, таких как файл изображения, BSON меньше JSON, так как двоичные данные не кодируются в кодировке Base64.
  • Документы BSON легко сканировать, так как элементы имеют префикс поля длины, поэтому средство синтаксического анализа может пропускать элементы, не декодируя их.
  • Кодирование и декодирование являются эффективными, так как числовые типы данных хранятся в виде чисел, а не строк.

Собственные клиенты, такие как клиентские приложения .NET, могут использовать BSON вместо текстовых форматов, таких как JSON или XML. Для клиентов браузера, вероятно, потребуется использовать JSON, так как JavaScript может напрямую преобразовывать полезные данные JSON.

К счастью, веб-API использует согласование содержимого, поэтому API может поддерживать оба формата и позволить клиенту выбирать.

Включение BSON на сервере

В конфигурации веб-API добавьте BsonMediaTypeFormatter в коллекцию formatters.

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Formatters.Add(new BsonMediaTypeFormatter());

        // Other Web API configuration not shown...
    }
}

Теперь, если клиент запрашивает "application/bson", веб-API будет использовать модуль форматирования BSON.

Чтобы связать BSON с другими типами мультимедиа, добавьте их в коллекцию SupportedMediaTypes. Следующий код добавляет application/vnd.contoso к поддерживаемым типам мультимедиа:

var bson = new BsonMediaTypeFormatter();
bson.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/vnd.contoso"));
config.Formatters.Add(bson);

Пример сеанса HTTP

В этом примере мы будем использовать следующий класс модели и простой контроллер веб-API:

public class Book
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Author { get; set; }
    public decimal Price { get; set; }
    public DateTime PublicationDate { get; set; }
}

public class BooksController : ApiController
{
    public IHttpActionResult GetBook(int id)
    {
        var book = new Book()
        {
            Id = id,
            Author = "Charles Dickens",
            Title = "Great Expectations",
            Price = 9.95M,
            PublicationDate = new DateTime(2014, 1, 20)
        };

        return Ok(book);
    }
}

Клиент может отправить следующий HTTP-запрос:

GET http://localhost:15192/api/books/1 HTTP/1.1
User-Agent: Fiddler
Host: localhost:15192
Accept: application/bson

Вот ответ:

HTTP/1.1 200 OK
Content-Type: application/bson; charset=utf-8
Date: Fri, 17 Jan 2014 01:05:40 GMT
Content-Length: 111

.....Id......Title.....Great Expectations..Author.....Charles Dickens..Price..........PublicationDate.........

Здесь я заменил двоичные данные символами ". На следующем снимке экрана из Fiddler показаны необработанные шестнадцатеричные значения.

Снимок экрана: панель окна, на которой показаны необработанные шестнадцатеричные значения двоичных данных в зеленом цвете в верхней и средней части и черном в нижней части.

Использование BSON с HttpClient

Приложения клиентов .NET могут использовать модуль форматирования BSON с HttpClient. Дополнительные сведения о HttpClient см. в статье Вызов веб-API из клиента .NET.

Следующий код отправляет запрос GET, который принимает BSON, а затем десериализует полезные данные BSON в ответе.

static async Task RunAsync()
{
    using (HttpClient client = new HttpClient())
    {
        client.BaseAddress = new Uri("http://localhost");

        // Set the Accept header for BSON.
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/bson"));

        // Send GET request.
        result = await client.GetAsync("api/books/1");
        result.EnsureSuccessStatusCode();

        // Use BSON formatter to deserialize the result.
        MediaTypeFormatter[] formatters = new MediaTypeFormatter[] {
            new BsonMediaTypeFormatter()
        };

        var book = await result.Content.ReadAsAsync<Book>(formatters);
    }
}

Чтобы запросить BSON с сервера, задайте для заголовка Accept значение application/bson:

client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new  
    MediaTypeWithQualityHeaderValue("application/bson"));

Для десериализации текста ответа используйте BsonMediaTypeFormatter. Этот модуль форматирования не входит в коллекцию модулей форматирования по умолчанию, поэтому его необходимо указать при чтении текста ответа:

MediaTypeFormatter[] formatters = new MediaTypeFormatter[] {
    new BsonMediaTypeFormatter()
};

var book = await result.Content.ReadAsAsync<Book>(formatters);

В следующем примере показано, как отправить запрос POST, содержащий BSON.

static async Task RunAsync()
{
    using (HttpClient client = new HttpClient())
    {
        client.BaseAddress = new Uri("http://localhost:15192");

        // Set the Accept header for BSON.
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/bson"));

        var book = new Book()
        {
            Author = "Jane Austen",
            Title = "Emma",
            Price = 9.95M,
            PublicationDate = new DateTime(1815, 1, 1)
        };

        // POST using the BSON formatter.
        MediaTypeFormatter bsonFormatter = new BsonMediaTypeFormatter();
        var result = await client.PostAsync("api/books", book, bsonFormatter);
        result.EnsureSuccessStatusCode();
    }
}

Большая часть этого кода совпадает с предыдущим примером. Но в методе PostAsync укажите BsonMediaTypeFormatter в качестве модуля форматирования:

MediaTypeFormatter bsonFormatter = new BsonMediaTypeFormatter();
var result = await client.PostAsync("api/books", book, bsonFormatter);

Сериализация Top-Level примитивных типов

Каждый документ BSON — это список пар "ключ-значение". Спецификация BSON не определяет синтаксис сериализации одного необработанного значения, например целого числа или строки.

Чтобы обойти это ограничение, BsonMediaTypeFormatter рассматривает примитивные типы как особый случай. Перед сериализацией он преобразует значение в пару "ключ-значение" с ключом "Значение". Например, предположим, что контроллер API возвращает целое число:

public class ValuesController : ApiController
{
    public IHttpActionResult Get()
    {
        return Ok(42);
    }
}

Перед сериализацией модуль форматирования BSON преобразует его в следующую пару "ключ-значение":

{ "Value": 42 }

При десериализации модуль форматирования преобразует данные обратно в исходное значение. Однако клиенты, использующие другое средство синтаксического анализа BSON, должны будут обрабатывать этот случай, если веб-API возвращает необработанные значения. Как правило, следует рассмотреть возможность возврата структурированных данных, а не необработанных значений.

Дополнительные ресурсы

Пример BSON веб-API

Модули форматирования мультимедиа