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

序列化頂層基本類型

每個 BSON 文件都是索引鍵/值組的清單。BSON 規範並未定義序列化單個原始值 (如整數或字串) 的語法。

為了解決此限制,BsonMediaTypeFormatter 會將基本類型視為特殊情況。 在序列化之前,它將值轉換為索引鍵/值組,其中索引鍵為「Value」。 例如,假設您的 API 控制器傳回一個整數:

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

在序列化之前,BSON 格式器會將其轉換為以下索引鍵/值組:

{ "Value": 42 }

還原序列化時,格式器會將資料轉換回原始值。 但是,如果您的 Web API 傳回原始值,則使用不同 BSON 解析器的用戶端將需要處理這種情況。 一般來說,您應該考慮傳回結構化資料,而不是原始值。

其他資源

Web API BSON 範例

媒體格式器