Supporto BSON in API Web ASP.NET 2.1
Questo argomento illustra come usare BSON nel controller API Web (lato server) e in un'app client .NET. L'API Web 2.1 introduce il supporto per BSON.
Che cos'è BSON?
BSON è un formato di serializzazione binaria. "BSON" è l'acronimo "Binary JSON", ma BSON e JSON vengono serializzati in modo molto diverso. BSON è "JSON-like", perché gli oggetti sono rappresentati come coppie nome-valore, simili a JSON. A differenza di JSON, i tipi di dati numerici vengono archiviati come byte, non stringhe
BSON è stato progettato per essere leggero, facile da analizzare e veloce da codificare/decodificare.
- BSON è paragonabile alle dimensioni a JSON. A seconda dei dati, un payload BSON può essere più piccolo o più grande di un payload JSON. Per la serializzazione dei dati binari, ad esempio un file di immagine, BSON è minore di JSON, perché i dati binari non sono codificati in base64.
- I documenti BSON sono facili da analizzare perché gli elementi sono preceduti da un campo di lunghezza, in modo che un parser possa ignorare gli elementi senza decodificarli.
- La codifica e la decodifica sono efficienti, perché i tipi di dati numerici vengono archiviati come numeri, non stringhe.
I client nativi, ad esempio le app client .NET, possono trarre vantaggio dall'uso di BSON al posto di formati basati su testo, ad esempio JSON o XML. Per i client del browser, probabilmente si vuole usare JSON perché JavaScript può convertire direttamente il payload JSON.
Fortunatamente, l'API Web usa la negoziazione del contenuto, in modo che l'API possa supportare entrambi i formati e consentire al client di scegliere.
Abilitazione di BSON nel server
Nella configurazione dell'API Web aggiungere BsonMediaTypeFormatter all'insieme di formattatori.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Formatters.Add(new BsonMediaTypeFormatter());
// Other Web API configuration not shown...
}
}
Ora, se il client richiede "application/bson", l'API Web userà il formattatore BSON.
Per associare BSON ad altri tipi di supporti, aggiungerli all'insieme SupportedMediaTypes. Il codice seguente aggiunge "application/vnd.contoso" ai tipi di supporti supportati:
var bson = new BsonMediaTypeFormatter();
bson.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/vnd.contoso"));
config.Formatters.Add(bson);
Sessione HTTP di esempio
Per questo esempio si userà la classe modello seguente e un semplice controller API Web:
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 client potrebbe inviare la richiesta HTTP seguente:
GET http://localhost:15192/api/books/1 HTTP/1.1
User-Agent: Fiddler
Host: localhost:15192
Accept: application/bson
Ecco la risposta:
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.........
Qui sono stati sostituiti i dati binari con caratteri ".". La schermata seguente di Fiddler mostra i valori esadecimali non elaborati.
Uso di BSON con HttpClient
Le app client .NET possono usare il formattatore BSON con HttpClient. Per altre informazioni su HttpClient, vedere Chiamata di un'API Web da un client .NET.
Il codice seguente invia una richiesta GET che accetta BSON e quindi deserializza il payload BSON nella risposta.
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);
}
}
Per richiedere BSON dal server, impostare l'intestazione Accept su "application/bson":
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new
MediaTypeWithQualityHeaderValue("application/bson"));
Per deserializzare il corpo della risposta, usare BsonMediaTypeFormatter. Questo formattatore non si trova nell'insieme di formattatori predefiniti, quindi è necessario specificarlo quando si legge il corpo della risposta:
MediaTypeFormatter[] formatters = new MediaTypeFormatter[] {
new BsonMediaTypeFormatter()
};
var book = await result.Content.ReadAsAsync<Book>(formatters);
Nell'esempio successivo viene illustrato come inviare una richiesta POST contenente 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 di questo codice è uguale all'esempio precedente. Ma nel metodo PostAsync specificare BsonMediaTypeFormatter come formattatore:
MediaTypeFormatter bsonFormatter = new BsonMediaTypeFormatter();
var result = await client.PostAsync("api/books", book, bsonFormatter);
Serializzazione di tipi primitivi Top-Level
Ogni documento BSON è un elenco di coppie chiave/valore. La specifica BSON non definisce una sintassi per la serializzazione di un singolo valore non elaborato, ad esempio un intero o una stringa.
Per risolvere questa limitazione, BsonMediaTypeFormatter considera i tipi primitivi come un caso speciale. Prima di serializzare, converte il valore in una coppia chiave/valore con la chiave "Valore". Si supponga, ad esempio, che il controller API restituisca un intero:
public class ValuesController : ApiController
{
public IHttpActionResult Get()
{
return Ok(42);
}
}
Prima di serializzare, il formattatore BSON converte questo valore nella coppia chiave/valore seguente:
{ "Value": 42 }
Quando si esegue la deserializzazione, il formattatore converte nuovamente i dati nel valore originale. Tuttavia, i client che usano un parser BSON diverso dovranno gestire questo caso, se l'API Web restituisce valori non elaborati. In generale, è consigliabile restituire dati strutturati anziché valori non elaborati.