【WebAPI No.5】Core WebAPI中的自定义格式化

简介: 介绍 Web API为JSON和XML提供媒体类型格式化程序。框架默认将这些格式化程序插入管道中。客户端可以在HTTP请求的Accept标头中请求JSON或XML. 格式化数据这个东西,其实没有什么最好的数据,要看各种场景,最适合才是最好的,不是说json就比xml好,容易解析什么的等。

介绍

Web API为JSON和XML提供媒体类型格式化程序。框架默认将这些格式化程序插入管道中。客户端可以在HTTP请求的Accept标头中请求JSON或XML.

格式化数据这个东西,其实没有什么最好的数据,要看各种场景,最适合才是最好的,不是说json就比xml好,容易解析什么的等。

废话不多说了,概念的东西大家一百度一大堆。开始我们的正文吧,当然首先我们还是要创建一个WebAPI项目,不会创建请返回第一章:如何创建简单的WebAPI项目

控制器的返回类型

特定类型:

首先我们最熟悉的就是特定类型了,比如stting或自定义对象类型等。就例如模版控制器的就是返回一个字符串数组类型:

     [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            return new string[] { "value1", "value2" };
        }

这种的示例没有已知条件,直接返回特定类型即可了 ,但是有些操作我们需要考虑已知的条件,这时候会返回多个返回结果。根据不同的条件返回对应结果,下面我们来看一下IActionResult 类型。

IActionResult 类型:

在多种情况条件返回多个不同结果时, 要支持此类操作,必须使用 IActionResult 或 ActionResult<T>。ActionResult类型表示多种的HTTP状态码。属于此类别的一些常见返回类型包括:

BadRequestResult (400)

NotFoundResult (404)

OkObjectResult (200)

在返回多个类型的时候我们如何返回不同的类型哪,我们可以借助【ProducesResponseType】特性来帮助我们实现返回自定义多个类型。下面我们写个简单的get方法的同步和异步的示例:

同步示例:

返回两个情况当id为5我给你正确返回,不是5我就找不到。当然实际情况肯定不是这个样子,但是就是打一个找资源的例子,找到就返回,找不到就返回404,。

 [HttpGet("{id}")]
        [ProducesResponseType(200, Type = typeof(Person))]
        [ProducesResponseType(404)]
        public IActionResult Get(int id)
        {
            if (id == 5)
            {
                return Ok(new Person
                {
                    Id = "001",
                    name = "姓名1",
                    age = 18,
                    Birthday = DateTime.Now,
                    introduce = "介绍001"
                });
            }
            else
            {
                return NotFound();
            }
            
        }
View Code

下面是异步的方法:

 [HttpGet("{id}")]
        [ProducesResponseType(200, Type = typeof(Person))]
        [ProducesResponseType(400)]
        public async Task<IActionResult> Get(int id)
        {
            if (id == 5)
            {
               
                await  Task.Run(()=>System.Threading.Thread.Sleep(1000));
                return Ok(new Person
                {
                    Id = "001",
                    name = "姓名1",
                    age = 18,
                    Birthday = DateTime.Now,
                    introduce = "介绍001"
                });
            }
            else
            {
                return BadRequest();
            }
            
        }
View Code

CreatedAtAction方法:创建一个CreatedAtActionResult对象,该对象生成Status201Created响应;具体想要了解的可以查看官方文档:CreatedAtAction方法介绍

 下面我们看一下请求结果:

id不是5的时候返回找不到:

id为5的时候正常返回咱们的对象:

 

 

ActionResult<T> 类型:

这个类型是从ASP.NET Core 2.1引入的,所有使用前请看下版本哦。它支持返回从 ActionResult 派生的类型或返回特定类型。 ActionResult<T> 通过 IActionResult 类型可提供以下优势:

  • 可排除 [ProducesResponseType] 特性的 Type 属性
  • 隐式强制转换运算符支持将 T 和 ActionResult 均转换为 ActionResult<T>  T 转换为 ObjectResult,也就是将 return new ObjectResult(T); 简化为 return T,什么个意思哪,说白了就是在定义的时候指定了类型直接return就可以了。

返回响应补充:

  • OK:创建一个OkResult对象,该对象生成一个空的Status200OK响应。
  • NoContentResult:没有内容,为响应创建的NoContentResult对象
  • NotFound():没有找到,为响应创建的NotFoundResult

  • PhysicalFile(string【文件的路径】,string【内容类型】):返回由physicalPathStatus200OK指定的文件。

  • Redirect(string【url】):重定向,为响应创建的RedirectResult。
  • StatusCode(int【返回的状态码】,object【值】):自定义返回状态,切附带返回值。其实是为响应创建了ObjectResult对象。

我就写部分常用的其他的有兴趣可以去官网了解一下:返回状态相应

自定义格式化程序

我们都知道WebAPI因为MVC的内置所以默认支持了json,xml和文本格式。那么我们想使用其他格式怎么办哪,微软总是不会让我们失望,我们可以自定义啊。

首先创建自定义格式化程序大致步骤:

  • 从相应的基类中派生类。
  • 在构造函数中指定有效的媒体类型和编码。
  • 重写 CanReadType/CanWriteType 方法
  • 重写 ReadRequestBodyAsync/WriteResponseBodyAsync 方法

从相应的基类中派生:

从那些类中派生官方给的解释是;

对于文本媒体类型(例如,vCard),从 TextInputFormatter 或 TextOutputFormatter 基类派生。

对于二进制类型,从 InputFormatter 或 OutputFormatter 基类派生。

例如官方示例:

public class VcardOutputFormatter : TextOutputFormatter

指定有效的媒体类型和编码

在构造函数中,通过添加到 SupportedMediaTypes 和 SupportedEncodings 集合来指定有效的媒体类型和编码。

public VcardOutputFormatter()
{
    SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/vcard"));

    SupportedEncodings.Add(Encoding.UTF8);
    SupportedEncodings.Add(Encoding.Unicode);
}

重写 CanReadType/CanWriteType

通过重写 CanReadType 或 CanWriteType 方法,指定可反序列化为或从其序列化的类型。 例如,可能只能从 Contact 类型创建 vCard 文本,反之亦然。

 

protected override bool CanWriteType(Type type)
{
    if (typeof(Contact).IsAssignableFrom(type) 
        || typeof(IEnumerable<Contact>).IsAssignableFrom(type))
    {
        return base.CanWriteType(type);
    }
    return false;
}

CanWriteResult方法不一定必须重写,但是有时候确实必须的,必须重写官方给的解释是;

  • 操作方法返回模型类。
  • 具有可能在运行时返回的派生类。
  • 需要知道操作在运行时返回了哪个派生类。

简单的意思是如果你返回的类型是父类的话,但是实际返回值可能存在子类型的返回且子类型为多个。但是你仅仅希望处理其中一个子类型的返回。这个时候可以使用CanWriteResult提供的上下文来检查对象类型。

重写 ReadRequestBodyAsync/WriteResponseBodyAsync

实际的反序列化或序列化工作在 ReadRequestBodyAsync 或 WriteResponseBodyAsync 中执行。 以下示例中突出显示的行展示了如何从依赖关系注入容器中获取服务(不能从构造函数参数中获取它们)

public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
{
    IServiceProvider serviceProvider = context.HttpContext.RequestServices;
    var logger = serviceProvider.GetService(typeof(ILogger<VcardOutputFormatter>)) as ILogger;

    var response = context.HttpContext.Response;

    var buffer = new StringBuilder();
    if (context.Object is IEnumerable<Contact>)
    {
        foreach (Contact contact in context.Object as IEnumerable<Contact>)
        {
            FormatVcard(buffer, contact, logger);
        }
    }
    else
    {
        var contact = context.Object as Contact;
        FormatVcard(buffer, contact, logger);
    }
    return response.WriteAsync(buffer.ToString());
}
View Code
private static void FormatVcard(StringBuilder buffer, Contact contact, ILogger logger)
{
    buffer.AppendLine("BEGIN:VCARD");
    buffer.AppendLine("VERSION:2.1");
    buffer.AppendFormat($"N:{contact.LastName};{contact.FirstName}\r\n");
    buffer.AppendFormat($"FN:{contact.FirstName} {contact.LastName}\r\n");
    buffer.AppendFormat($"UID:{contact.ID}\r\n");
    buffer.AppendLine("END:VCARD");
    logger.LogInformation($"Writing {contact.FirstName} {contact.LastName}");
}
View Code

 官方示例DOME下载

 传送门

WebApi系列文章目录介绍

作者:YanBigFeg —— 颜秉锋

出处:http://www.cnblogs.com/yanbigfeg

本文版权归作者和博客园共有,欢迎转载,转载请标明出处。如果您觉得本篇博文对您有所收获,觉得小弟还算用心,请点击右下角的 [推荐],谢谢!

目录
相关文章
|
XML 数据可视化 程序员
(一).NET Core WebAPI集成Swagger做接口管理
什么是Swagger? Swagger 是一个规范且完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。 Swagger 的目标是对 REST API 定义一个标准且和语言无关的接口,可以让人和计算机拥有无须访问源码、文档或网络流量监测就可以发现和理解服务的能力。当通过 Swagger 进行正确定义,用户可以理解远程服务并使用最少实现逻辑与远程服务进行交互。与为底层编程所实现的接口类似,Swagger 消除了调用服务时可能会有的猜测。 Swagger 有什么优势? 支持 API 自动生成同步的在线文档:使用 Swagger 后可以直接通过代码生成文档,不再需
(一).NET Core WebAPI集成Swagger做接口管理
|
4月前
|
开发框架 .NET 数据库连接
闲话 Asp.Net Core 数据校验(三)EF Core 集成 FluentValidation 校验数据例子
闲话 Asp.Net Core 数据校验(三)EF Core 集成 FluentValidation 校验数据例子
|
JSON 开发框架 .NET
ASP.NET Core: 二十一. 内容协商与自定义IActionResult和格式化类(一)
上一章的结尾留下了一个问题:同样是ObjectResult,在执行的时候又是如何被转换成string和JSON两种格式的呢? 本章来解答这个问题,这里涉及到一个名词:“内容协商”。除了这个,本章将通过两个例子来介绍如何自定义IActionResult和格式化类。
346 0
ASP.NET Core: 二十一. 内容协商与自定义IActionResult和格式化类(一)
|
XML 开发框架 JSON
ASP.NET Core: 二十一. 内容协商与自定义IActionResult和格式化类(五)
上一章的结尾留下了一个问题:同样是ObjectResult,在执行的时候又是如何被转换成string和JSON两种格式的呢? 本章来解答这个问题,这里涉及到一个名词:“内容协商”。除了这个,本章将通过两个例子来介绍如何自定义IActionResult和格式化类。
230 0
ASP.NET Core: 二十一. 内容协商与自定义IActionResult和格式化类(五)
|
JSON 开发框架 .NET
ASP.NET Core: 二十一. 内容协商与自定义IActionResult和格式化类(四)
上一章的结尾留下了一个问题:同样是ObjectResult,在执行的时候又是如何被转换成string和JSON两种格式的呢? 本章来解答这个问题,这里涉及到一个名词:“内容协商”。除了这个,本章将通过两个例子来介绍如何自定义IActionResult和格式化类。
171 0
ASP.NET Core: 二十一. 内容协商与自定义IActionResult和格式化类(四)
|
缓存 API 网络架构
WebAPI简介
有三个核心:资源(resource),URL(统一资源标识符)和表示
346 0
WebAPI简介
|
存储 缓存 前端开发
为什么我要推荐你使用Core WebApi?
为什么我要推荐你使用Core WebApi?
281 0
为什么我要推荐你使用Core WebApi?
|
JSON 开发框架 .NET
ASP.NET Core: 二十一. 内容协商与自定义IActionResult和格式化类(三)
上一章的结尾留下了一个问题:同样是ObjectResult,在执行的时候又是如何被转换成string和JSON两种格式的呢? 本章来解答这个问题,这里涉及到一个名词:“内容协商”。除了这个,本章将通过两个例子来介绍如何自定义IActionResult和格式化类。
397 0
|
JSON 开发框架 .NET
ASP.NET Core: 二十一. 内容协商与自定义IActionResult和格式化类(二)
上一章的结尾留下了一个问题:同样是ObjectResult,在执行的时候又是如何被转换成string和JSON两种格式的呢? 本章来解答这个问题,这里涉及到一个名词:“内容协商”。除了这个,本章将通过两个例子来介绍如何自定义IActionResult和格式化类。
283 0
|
.NET API 数据格式
Asp.Net Core WebAPI使用Swagger时API隐藏与分组
Asp.Net Core WebAPI使用Swagger时API隐藏与分组1、前言为什么我们要隐藏部分接口? 因为我们在用swagger代替接口的时候,难免有些接口会直观的暴露出来,比如我们结合Consul一起使用的时候,会将健康检查接口以及报警通知接口暴露出来,这些接口有时候会出于方便考虑,没有进行加密,这个时候我们就需要把接口隐藏起来,只有内部的开发者知道。
2758 0