Media Formatters in ASP.NET Web API 2

原文:http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters

1. 网络媒体类型

媒体类型,也叫作MIME类型,表示数据的格式。在HTTP中,MIME描述了消息体的格式。

  • MIME类型有两个字符串组成——类型和子类型。例如:
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头部告诉服务器客户端想要什么类型的MIME类型。例如:
Accept: text/html,application/xhtml+xml,application/xml

这个头部告诉服务器,客户端想要HTML,XHTML,或者XML。

  • MIME类型决定了WEB API怎么序列化和反序列化HTTP的消息体。WEB API有内置的MIME,支持XML,JSON,BSON,以及form-urlencoded数据,也可以通过自定义一个媒体格式。

为了创建一个MIME格式,从以下其中一个类派生:

  • MediaTypeFormatter. 这个类使用异步的读写方法。

  • BufferedMediaTypeFormatter. 这个类从MediaTypeFormatter 派生,但是使用同步的读写方法。

2. 示例:创建一个CSV媒体格式

Steps:

  1. 创建一个ProductCsvFormatter
  2. 构造函数添加支持的媒体类型
  3. 重写CanWriteType,表明可以序列化的类型
  4. 重写CanReadType,表明可以反序列化的类型
  5. 重写WriteToStream,序列化的真正实现
  6. 将媒体格式添加到WEB API管道
  7. 添加字符编码支持,支持UTF-8,iso-8859-1
  8. 增加测试代码

ProductCsvFormatter 代码片段

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

namespace WebApiPractice.Formatters
{
    //http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters
    //Step1
    public class ProductCsvFormatter: BufferedMediaTypeFormatter
    {
        public ProductCsvFormatter()
        {
            //Step2
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));

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

        //Step3
        public override bool CanWriteType(Type type)
        {
            if(type == typeof(Product))
            {
                return true;
            }

            Type enumerableType = typeof(IEnumerable<Product>);
            return enumerableType.IsAssignableFrom(type);
        }

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

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

            using (var writer = new StreamWriter(writeStream, effectiveEncoding))
            {
                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[] { ',', '
', '
', '"' };

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

WebApiConfig代码片段

using System.Web.Http;
using Microsoft.Owin.Security.OAuth;
using WebApiPractice.Formatters;

namespace WebApiPractice
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 配置和服务
            // 将 Web API 配置为仅使用不记名令牌身份验证。
            config.SuppressDefaultHostAuthentication();
            config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

            // Web API 路由
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            //Step6,加入web api管道
            config.Formatters.Add(new ProductCsvFormatter());
        }
    }
}

测试代码

using System;
using System.Net.Http;
using System.Net.Http.Headers;

namespace WebApiPractice
{
    public class WebApiRequestHelper
    {
        public void Start()
        {
            HttpClient httpClient = new HttpClient();
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/csv", 1));

            var t = httpClient.GetStringAsync("http://localhost:60865/api/products");
            t.Wait();

            System.Diagnostics.Debug.WriteLine(t.Result);
            Console.WriteLine(t.Result);
        }
    }
}

测试结果

1,Tomato Soup,Groceries,1
2,Yo-yo,Toys,3.75
3,Hammer,Hardware,16.99
原文地址:https://www.cnblogs.com/pengzhen/p/5836832.html