• Media Formatters(媒体格式化器)


    6.1.1 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期间可能会阻塞线程。

    6.1.2 创建媒体格式化器

    以下示例演示了一个媒体类型格式化器,它可以将Product对象序列化成一个逗号分隔的值(CSV)格式。该示例使用了“创建支持CRUD操作的Web API”教程中定义的Product类型。以下是Product对象的定义:

        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的类:

        public class ProductCsvFormatter : BufferedMediaTypeFormatter 
        {
        }

    在其构造器中,要添加一个该格式化器所支持的媒体类型。在这个例子中,该格式化器只支持单一的媒体类型:“text/csv”:

    public ProductCsvFormatter()
    {
        // 添加所支持的媒体类型
        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(); } // 将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[] { ',', ' ', ' ', '"' };
    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; }


    6.1.4 添加媒体格式化器

    为了将媒体类型格式化器添加到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();
    // 添加Accept报头 client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/csv"));
    // 获取结果并将其写入文件 // (端口号9000只是一个示例端口号) string result = client.GetStringAsync("http://localhost:9000/api/product/").Result;
  • 相关阅读:
    关于面向对象和面象过程的一些感想
    面向对象之旅软件生命周期
    函数参数栈传递
    看完后停下来想想我们究竟在追求什么???
    面向对象之旅设计与设计原则
    [译]多重继承和虚继承的内存布局
    61条面向对象设计的经验原则
    数据库设计14个技巧(转)
    js的tween
    三、windows8 store
  • 原文地址:https://www.cnblogs.com/fanfan-90/p/12050976.html
Copyright © 2020-2023  润新知