三、 自定义格式化类
对于上一节的例子,也可以对照JsonOutputFormatter来自定义一个格式化类来实现。将新定义一个名为BookOutputFormatter的类,也如同JsonOutputFormatter一样继承TextOutputFormatter。代码如下:
public class BookOutputFormatter : TextOutputFormatter { public BookOutputFormatter() { SupportedEncodings.Add(Encoding.UTF8); SupportedEncodings.Add(Encoding.Unicode); SupportedMediaTypes.Add("text/book"); } public override bool CanWriteResult(OutputFormatterCanWriteContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (context.ObjectType == typeof(Book) || context.Object is Book) { return base.CanWriteResult(context); } return false; } private static string FormatToString(Book book) { return string.Format("Book Code:[{0}]|Book Name:<{1}>",book.Code,book.Name); } public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (selectedEncoding == null) { throw new ArgumentNullException(nameof(selectedEncoding)); } var valueAsString = FormatToString(context.Object as Book); if (string.IsNullOrEmpty(valueAsString)) { await Task.CompletedTask; } var response = context.HttpContext.Response; await response.WriteAsync(valueAsString, selectedEncoding); } }
首先在构造函数中定义它所支持的字符集和Content-type类型。重写CanWriteResult方法,这是用于确定它是否能处理对应的请求返回结果。可以在此方法中做多种判断,最终返回bool类型的结果。本例比较简单,仅是判断返回的结果是否为Book类型。同样定义了FormatToString方法用于请求结果的格式化。最后重写WriteResponseBodyAsync方法,将格式化后的结果写入Response.Body中。
BookOutputFormatter定义之后也需要注册到系统中去,例如如下代码:
services.AddMvc( options => { options.OutputFormatters.Insert(0,new BookOutputFormatter()); } )
这里采用了Insert方法,也就是将其插入了OutputFormatters集合的第一个。所以在筛选OutputFormatters的时候,它也是第一个。此时的OutputFormatters如下图 3
图 3
通过Fiddler测试一下,以第一节返回Book类型的第4个例子为例:
1.public Book GetModel() { return new Book() { Code = "1001", Name = "ASP" }; }
当设定accept: text/book或者未设定accept的时候,采用了自定义的BookOutputFormatter,返回结果为:
Book Code:[1001]|Book Name:<ASP>
Content-Type值是:Content-Type: text/book; charset=utf-8。
当设定accept: application/json的时候,返回JSON,值为:
{"code":"1001","name":"ASP"}
Content-Type值是:Content-Type: application/json; charset=utf-8。
这是由于BookOutputFormatter类型排在了JsonOutputFormatter的前面,所以对于Book类型会首先采用BookOutputFormatter,当客户端通过Accept方式要求返回结果为JSON的时候,才采用了JSON类型。测试一下服务端的要求。将这个Action添加Produces设置,代码如下:
[Produces("application/json")] public Book GetModel() { return new Book() { Code = "1001", Name = "ASP" }; }
此时无论设定accept: text/book或者未设定accept的情况,都会按照JSON的方式返回结果。这也验证了第二节关于服务端和客户端“协商”的规则。