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[] { ',', '\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;
}

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;

最新文章

  1. [LeetCode] Palindrome Number 验证回文数字
  2. checking for fcc ....no checking for cc .. no
  3. springmvc注解配置
  4. Linux 下Valgrind 使用
  5. PD code与name联动(取消)设置
  6. JQUERY1.9学习笔记 之基本过滤器(五) 大于选择器
  7. C期未考试参考答案
  8. tomcat编译通过问题
  9. 获得mysql内容,生成xml文件,另外,为了webservice发送
  10. D6
  11. 修改某个UITextField的键盘的返回键类型以及监听键盘的高度变化,取到键盘动画退出弹出的时间,一起随着键盘顶出来或者压下去,
  12. BinarySearch的一些注意事项
  13. 一个普通的 Zepto 源码分析(二) - ajax 模块
  14. Html行内元素和块级元素
  15. win7 64位专业版下的x64编译问题
  16. 安卓Android基础第五天
  17. Dotest-两张图告诉你,为什么要测试兼容性?
  18. 图解android开发在界面上显示图片
  19. phpstorm怎么设置每个function都用那条横线隔开
  20. Shell脚本的学习(二)

热门文章

  1. Luogu P3646 [APIO2015]巴厘岛的雕塑
  2. FAQ简介
  3. How does Chrome Extension crx Downloader work? ——— From crxdown.com
  4. [NewLife.XCode]实体工厂(拦截处理实体操作)
  5. HTML连载25-通配符选择器&amp;选择器综合练习
  6. java优化细节记录
  7. 全链路跟踪TraceId
  8. $.Ajax、$.Get、$.Post代码实例参数解析
  9. Zabbix图表中文乱码(包含Docker安装乱码)
  10. GO学习笔记 - 模版渲染及多种输出