Asp.Net Web API 2第十二課——Media Formatters媒體格式化器


前言

閱讀本文之前,您也可以到Asp.Net Web API 2 系列導航進行查看 http://www.cnblogs.com/aehyok/p/3446289.html

本教程演示如何在ASP.NET Web API中支持額外的媒體格式。

Internet Media Types——Internet的媒體類型

媒體類型,也叫做MIME類型,標識了一片數據的格式。在HTTP中,媒體類型描述了消息體的格式。一個媒體類型由兩個字符串組成:類型和子類型。例如:

  • 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中,媒體類型決定了Web API如何對HTTP消息體進行序列化和反序列化。對於XML、JSON,以及URL編碼的表單數據,已有了內建的支持。而且,通過編寫媒體格式化器(Media Formatter),可以支持額外的媒體類型。

為了創建媒體格式化器,需從以下類進行派生:

  • MediaTypeFormatter。這個類使用了異步讀寫方法
  • BufferedMediaTypeFormatter。這個類派生於MediaTypeFormatter,但將異步讀寫方法封裝在同步方法之中。

從BufferedMediaTypeFormatter派生要更簡單些,因為沒有異步代碼,但它也意味着在I/O期間可能會阻塞線程。

Creating a Media Formatter——創建媒體格式化器

 以下示例演示了一個媒體類型格式化器,它可以將Product對象序列化成一個逗號分隔的值(CSV)格式。該示例使用了Asp.Net Web API 2第二課——CRUD操作  http://www.cnblogs.com/aehyok/p/3434578.html中定義的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格式化器,要定義一個派生於BufferedMediaTypeFormater的類:

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

    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。

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

最后,重寫WriteToStream方法。通過將一種類型寫成一個流,該方法對該類型進行序列化。如果你的格式化器要支持反序列化,也可以重寫ReadFromStream方法。

public override void WriteToStream(
    Type type, object value, Stream stream, HttpContentHeaders contentHeaders)
{
    using (var writer = new StreamWriter(stream))
    {
        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);
        }
    }
    stream.Close();
}
// Helper methods for serializing Products to CSV format. 
// 將Product序列化成CSV格式的輔助器方法
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)
    {
        return String.Format("\"{0}\"", field.Replace("\"", "\"\""));
    }
    else return field;
}

Adding the Media Formatter——添加媒體格式化器

 為了將媒體類型格式化器添加到Web API管線,要使用HttpConfiguration對象上的Formatters屬性。

 

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

對於ASP.NET托管,要將這個函數添加到Global.asax文件,並通過Application_Start方法調用它。

protected void Application_Start()
{
    ConfigureApis(GlobalConfiguration.Configuration);

    // ...
}

現在,如果客戶端在Accept報頭指定“text/csv”,則服務器將返回CSV格式的數據。

以下示例使用HttpClient來獲取CSV數據,並將其寫入一個文件:

 

HttpClient client = new HttpClient();

// Add the Accept header
// 添加Accept報頭
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/csv"));

// Get the result and write it to a file.
// (Port 9000 is just an example port number.)
// 獲取結果並將其寫入文件
// (端口號9000只是一個示例端口號)
string result = client.GetStringAsync("http://localhost:9000/api/product/").Result;
System.IO.File.WriteAllText("products.csv", result);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM