• 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[] { ',', '
    ', '
    ', '"' };
    
    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);
  • 相关阅读:
    电信生命周期说明
    find in linux 2 微信公众号
    GDB中应该知道的几个调试方法 2 微信公众号
    linux 下程序员专用搜索源码用来替代grep的软件ack(后来发现一个更快的: rg), 且有vim插件的 2 微信公众号
    linux下的 c 和 c++ 开发工具及linux内核开发工具 2 微信公众号
    linux下命令行发送邮件的软件:mutt 微信公众号
    腺样体肿大的综合治疗考虑 微信公众号
    打呼噜治疗方法 微信公众号
    vim 操作 2 微信公众号
    nginx之外的web 服务器caddy 微信公众号
  • 原文地址:https://www.cnblogs.com/dwuge/p/5331713.html
Copyright © 2020-2023  润新知