ASP.NET Web API 2.1 中的 BSON 支持
本主题演示如何在 Web API 控制器 (服务器端) 和 .NET 客户端应用中使用 BSON。 Web 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 有效负载。
幸运的是,Web API 使用 内容协商,因此 API 可以支持这两种格式,并允许客户端选择。
在服务器上启用 BSON
在 Web API 配置中,将 BsonMediaTypeFormatter 添加到格式化程序集合。
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Formatters.Add(new BsonMediaTypeFormatter());
// Other Web API configuration not shown...
}
}
现在,如果客户端请求“application/bson”,Web API 将使用 BSON 格式化程序。
若要将 BSON 与其他媒体类型相关联,请将它们添加到 SupportedMediaTypes 集合。 以下代码将“application/vnd.contoso”添加到支持的媒体类型:
var bson = new BsonMediaTypeFormatter();
bson.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/vnd.contoso"));
config.Formatters.Add(bson);
示例 HTTP 会话
对于此示例,我们将使用以下模型类和一个简单的 Web 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 的详细信息,请参阅 从 .NET 客户端调用 Web API。
以下代码发送接受 BSON 的 GET 请求,然后在响应中反序列化 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);
下一个示例演示如何发送包含 BSON 的 POST 请求。
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 将基元类型视为特殊情况。 在序列化之前,它会将值转换为带有键“Value”的键/值对。 例如,假设 API 控制器返回一个整数:
public class ValuesController : ApiController
{
public IHttpActionResult Get()
{
return Ok(42);
}
}
在序列化之前,BSON 格式化程序将其转换为以下键/值对:
{ "Value": 42 }
反序列化时,格式化程序会将数据转换回原始值。 但是,如果 Web API 返回原始值,则使用不同的 BSON 分析器的客户端将需要处理这种情况。 通常,应考虑返回结构化数据,而不是原始值。