Compatibilidad con BSON en ASP.NET Web API 2.1

En este tema se muestra cómo usar BSON en un controlador de Web API (lado servidor) y en una aplicación cliente de .NET. Web API 2.1 tiene compatibilidad con BSON.

¿Qué es BSON?

BSON es un formato de serialización binario. "BSON" significa "JSON binario", pero BSON y JSON se serializan de forma muy diferente. BSON es "similar a JSON", ya que los objetos se representan en forma de pares nombre-valor, tal como se hace en JSON. A diferencia de JSON, los tipos de datos numéricos se almacenan en forma de bytes, no de cadenas.

BSON se diseñó para ser ligero, fácil de examinar y rápido para codificar o descodificar.

  • El tamaño de BSON es similar al de JSON. En función de los datos, una carga BSON puede ser menor o mayor que una carga JSON. Para serializar datos binarios, como un archivo de imagen, BSON es más pequeño que JSON, ya que los datos binarios no están codificados en base64.
  • Los documentos de BSON son fáciles de examinar, ya que su prefijo es un campo de longitud, por lo que un analizador puede omitir elementos sin descodificarlos.
  • La codificación y decodificación son eficaces, ya que los tipos de datos numéricos se almacenan como números, no como cadenas.

Los clientes nativos, como las aplicaciones cliente de .NET, pueden beneficiarse del uso de BSON, en lugar de formatos basados en texto como JSON o XML. En el caso de los clientes de explorador, probablemente quiera seguir con JSON, ya que JavaScript puede convertir directamente la carga de JSON.

Afortunadamente, la API web usa la negociación de contenido, por lo que la API puede admitir ambos formatos y permitir que el cliente elija.

Habilitación de BSON en el servidor

En la configuración de la API web, agregue BsonMediaTypeFormatter a la colección de formateadores.

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

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

De esta forma, si el cliente solicita "application/bson", la API web usará el formateador BSON.

Para asociar BSON con otros tipos de soportes físicos, agréguelos a la colección SupportedMediaTypes. El código siguiente agrega "application/vnd.contoso" a los tipos de soportes técnicos admitidos:

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

Sesión HTTP de ejemplo

En este ejemplo, usaremos la siguiente clase de modelo más un controlador de API web simple:

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);
    }
}

Un cliente puede enviar la siguiente solicitud HTTP:

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

Esta es la respuesta:

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.........

Aquí se han reemplazado los datos binarios por caracteres ".". La siguiente captura de pantalla de Fiddler muestra los valores hexadecimales sin procesar.

Screenshot of a window pane showing the binary data's raw hex values in the colors green on the top and middle, and black at the bottom.

Uso de BSON con HttpClient

Las aplicaciones de clientes .NET pueden usar el formateador BSON con HttpClient. Para más información sobre HttpClient, consulte Llamar a una Web API desde un cliente .NET.

El siguiente código envía una solicitud GET que acepta BSON y, después, deserializa la carga de BSON en la respuesta.

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);
    }
}

Para solicitar BSON desde el servidor, establezca el encabezado Accept en "application/bson":

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

Para deserializar el cuerpo de la respuesta, use BsonMediaTypeFormatter. Este formateador no se encuentra en la colección de formateadores predeterminados, por lo que debe especificarlo al leer el cuerpo de la respuesta:

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

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

En el ejemplo siguiente se muestra cómo enviar una solicitud POST que contiene 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();
    }
}

Gran parte de este código es el mismo que el del ejemplo anterior. Pero en el método PostAsync, especifique BsonMediaTypeFormatter como formateador:

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

Serialización de tipos primitivos de máximo nivel

Cada documento de BSON es una lista de pares clave-valor. La especificación de BSON no define una sintaxis para serializar un único valor sin procesar, como un entero o una cadena.

Para solucionar esta limitación, BsonMediaTypeFormatter trata los tipos primitivos como un caso especial. Antes de serializar, convierte el valor en un par clave-valor con la clave "Value". Por ejemplo, supongamos que el controlador de API devuelve un entero:

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

Antes de serializar, el formateador BSON lo convierte en el siguiente par clave-valor:

{ "Value": 42 }

Al deserializar, el formateador vuelve a convertir los datos en el valor original. Sin embargo, los clientes que usen otro analizador de BSON tendrán que controlar este caso, si la API web devuelve valores sin procesar. En general, debe considerar la posibilidad de devolver datos estructurados, en lugar de valores sin procesar.

Recursos adicionales

Ejemplo de BSON de API web

Formateadores de soportes físicos