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 分析器的客户端将需要处理这种情况。 通常,应考虑返回结构化数据,而不是原始值。

其他资源

Web API BSON 示例

媒体格式化程序