共用方式為


ASP.NET Web API 2 中的媒體格式器

本教學課程示範如何在 ASP.NET Web API 中支援其他媒體格式。

網路媒體類型

媒體類型,也稱為 MIME 類型,用於識別一段資料的格式。 在 HTTP 中,媒體類型描述了訊息本文的格式。 媒體類型由兩個字串組成,一個是類型 (type),另一個是子類型 (subtype)。 例如:

  • text/html
  • image/png
  • application/json

當 HTTP 訊息包含實體主體時,Content-Type 標頭指定了訊息主體的格式。 這告訴接收者如何解析訊息本文的內容。

例如,如果 HTTP 回應包含 PNG 影像,則該回應可能具有下列標頭。

HTTP/1.1 200 OK
Content-Length: 95267
Content-Type: image/png

當用戶端傳送請求訊息時,可以包含 Accept 標頭。 Accept 標頭告訴伺服器用戶端希望從伺服器取得哪種媒體類型。 例如:

Accept: text/html,application/xhtml+xml,application/xml

該標頭告訴伺服器用戶端需要 HTML、XHTML 還是 XML。

媒體類型決定 Web API 如何序列化和還原序列化 HTTP 訊息本文。 Web API 內建了對 XML、JSON、BSON 和表單 urlencoded 資料的支援,您可以透過撰寫媒體格式器來支援其他媒體類型。

若要建立媒體格式器,請從下列其中一個類別衍生:

BufferedMediaTypeFormatter 衍生更簡單,因為沒有非同步程式碼,但這也代表呼叫執行緒在 I/O 期間可能會阻塞。

範例:建立 CSV 媒體格式器

以下範例顯示了一個媒體類型格式器,它可以將 Product 物件序列化為逗號分隔值 (CSV) 格式。 這個範例使用了在教學課程「建立支援 CRUD 操作的 Web API」中定義的 Product 類型。 以下是 Product 物件的定義:

namespace ProductStore.Models
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Category { get; set; }
        public decimal Price { get; set; }
    }
}

若要實作 CSV 格式器,請定義一個衍生自 BufferedMediaTypeFormatter 的類別:

using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using ProductStore.Models;

namespace ProductStore.Formatters
{
    public class ProductCsvFormatter : BufferedMediaTypeFormatter
    {
    }
}

在建構函式中,新增格式器支援的媒體類型。 在此範例中,格式器支援單一媒體類型「text/csv」:

public ProductCsvFormatter()
{
    // Add the supported media type.
    SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));
}

覆寫 CanWriteType 方法以指示格式器可以序列化哪些類型:

public override bool CanWriteType(System.Type type)
{
    if (type == typeof(Product))
    {
        return true;
    }
    else
    {
        Type enumerableType = typeof(IEnumerable<Product>);
        return enumerableType.IsAssignableFrom(type);
    }
}

在此範例中,格式器可以序列化單一 Product 物件以及 Product 物件集合。

同樣,覆寫 CanReadType 方法以指示格式器可以還原序列化的類型。 在此範例中,格式器不支援還原序列化,因此該方法只會傳回 False

public override bool CanReadType(Type type)
{
    return false;
}

最後,覆寫 WriteToStream 方法。 此方法透過將類型寫入串流來序列化類型。 如果您的格式器支援還原序列化,還需覆寫 ReadFromStream 方法。

public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent content)
{
    using (var writer = new StreamWriter(writeStream))
    {
        var products = value as IEnumerable<Product>;
        if (products != null)
        {
            foreach (var product in products)
            {
                WriteItem(product, writer);
            }
        }
        else
        {
            var singleProduct = value as Product;
            if (singleProduct == null)
            {
                throw new InvalidOperationException("Cannot serialize type");
            }
            WriteItem(singleProduct, writer);
        }
    }
}

// Helper methods for serializing Products to CSV format. 
private void WriteItem(Product product, StreamWriter writer)
{
    writer.WriteLine("{0},{1},{2},{3}", Escape(product.Id),
        Escape(product.Name), Escape(product.Category), Escape(product.Price));
}

static char[] _specialChars = new char[] { ',', '\n', '\r', '"' };

private string Escape(object o)
{
    if (o == null)
    {
        return "";
    }
    string field = o.ToString();
    if (field.IndexOfAny(_specialChars) != -1)
    {
        // Delimit the entire field with quotes and replace embedded quotes with "".
        return String.Format("\"{0}\"", field.Replace("\"", "\"\""));
    }
    else return field;
}

將媒體格式器新增至 Web API 管線

若要將媒體類型格式器新增至 Web API 管線,請使用 HttpConfiguration 物件上的 Formatters 屬性。

public static void ConfigureApis(HttpConfiguration config)
{
    config.Formatters.Add(new ProductCsvFormatter()); 
}

字元編碼

或者,媒體格式器可以支援多種字元編碼,例如 UTF-8 或 ISO 8859-1。

在建構函式中,將一種或多種 System.Text.Encoding 類型新增至 SupportedEncodings 集合中。 將預設編碼放在第一位。

public ProductCsvFormatter()
{
    SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));

    // New code:
    SupportedEncodings.Add(new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
    SupportedEncodings.Add(Encoding.GetEncoding("iso-8859-1"));
}

WriteToStreamReadFromStream 方法中,呼叫 MediaTypeFormatter.SelectCharacterEncoding 選擇慣用字元編碼。 此方法將請求標頭與支援的編碼清單進行比對。 從串流中讀取或寫入時使用傳回的編碼

public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent content)
{
    Encoding effectiveEncoding = SelectCharacterEncoding(content.Headers);

    using (var writer = new StreamWriter(writeStream, effectiveEncoding))
    {
        // Write the object (code not shown)
    }
}