开发者社区> yanbigfeg> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

【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

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

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
推荐一种通过刷leetcode来增强技术功底的方法
如果前人认为这个一种学习提高或者检验能力的成功实践。而自己目前又没有更好的方法,那就不妨试一试。 而不管作为面试官还是被面试者,编码题最近越来越流行。而两种角色都需要思考的问题是希望考察什么能力,通过什么题目,需要达到怎样的程度可以说明面试者具有了这样的能力。 而要找到上面这些问题的答案,比较好的方式除了看一些理论性文章和接受培训之外,自己动手刷一刷leetcode切身实践一下不失为一个不错的方式。而既然要花精力去做这件事情,那就需要解决一个问题:我从中可以获得什么提高。以下是个人的一些经验和感受。
35 0
版本化ASP.NET Core WebApi
版本化ASP.NET Core WebApi
26 0
十万亿级OLAP引擎解读-AnalyticDB如何支撑数据银行超大规模低成本实时分析
数据银行是一款品牌消费者运营的商业数据产品,由于其核心分析能力需要在海量数据上实现任意维度自由分析和响应时间上的强需求,我们大规模使用AnalyticDB作为底层的分析引擎,最终以较低的成本,出色的性能,支撑了上万品牌商大促期间每天百万级的OLAP查询。
490 0
十万亿级OLAP引擎解读-AnalyticDB如何支撑数据银行超大规模低成本实时分析
数据银行是一款品牌消费者运营的商业数据产品,由于其核心分析能力需要在海量数据上实现任意维度自由分析和响应时间上的强需求,我们大规模使用AnalyticDB作为底层的分析引擎,最终以较低的成本,出色的性能,支撑了上万品牌商大促期间每天百万级的OLAP查询。
3594 0
ASP.NET Core - 实现自定义WebApi模型验证
ASP.NET Core - 实现自定义WebApi模型验证  Framework时代    在Framework时代,我们一般进行参数验证的时候,以下代码是非常常见的 复制代码 [HttpPost] public async Task<JsonResult> SaveNewCus...
1381 0
Asp.Net Core WebAPI使用Swagger时API隐藏与分组
Asp.Net Core WebAPI使用Swagger时API隐藏与分组1、前言为什么我们要隐藏部分接口? 因为我们在用swagger代替接口的时候,难免有些接口会直观的暴露出来,比如我们结合Consul一起使用的时候,会将健康检查接口以及报警通知接口暴露出来,这些接口有时候会出于方便考虑,没有进行加密,这个时候我们就需要把接口隐藏起来,只有内部的开发者知道。
2326 0
Web API的CORS
Web API中进行跨域需要在请求头中加入允许跨域请求 Access-Control-Allow-Origin=*  上面代码代表允许所有跨域请求。当然也可以只允许某个站点进行跨域请求,只需将‘*’改为指定站定即可 Access-Control-Allow-Origin=“http://www.
792 0
.net 中 前台aspx页面调用后台.cs文件中的变量
定义全局变量 在Page_load上面写 public string Url;     后台代码: public partial class WebForm2 : System.Web.
934 0
+关注
63
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载