

【ASP.NET Core】设置Web API 响应的数据格式——Produces 特性篇
source link: https://www.cnblogs.com/tcjiaan/p/15865531.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

【ASP.NET Core】设置Web API 响应的数据格式——Produces 特性篇
开春首文,今天老周就跟各位大伙伴们聊一个很简单的话题:怎么设定API响应的数据格式。
说本质一点,就是设置所返回内容的 MIME 类型(Content-Type 头)。当然了,咱们不会使用在HTTP管道中插入中间件的方式来解决,因为:
A、这样做会导致所有传入传出的HTTP消息都被修改;
B、这样会毁坏API应用的设计规范,弄得不伦不类、礼崩乐坏、不堪入目。
所以,今天的主角是一个特性类(Attribute),它的大名叫 ProducesAttribute,位于 Microsoft.AspNetCore.Mvc 命名空间下。这么一介绍,你肯定能找到它。
根据定义,该特性类可用于:类、方法。说得再直接一点,就是用于 Controller类 和 Action方法。
这个特性类用于 设置API返回数据的MIME类型,嗯,也就是所谓的格式了。最人性化最简单的使用方法就是这样:
[Produces("text/html")] [Produces("audio/wav")] [Produces("image/png")] [Produces("application/octet-stream")]
就是这样,你希望返回的是啥东西,就用 Content-Type 字符串来指定。
马上,立刻,现在,就给大伙儿演示一个例子,让 API 返回 text/json 类型的数据。因为默认情况下,API 返回数据使用 application/json 格式,所以,咱们要改为 text/json,就得用 Produces 特性。
首先,新建一个空的 ASP.NET Core 应用项目。老周喜欢空模板,易于 DIY,可折腾性强。
然后,在 Program.cs 文件中注册与 MVC 控制器有关的服务,以及Map一下相关中间件。
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); var app = builder.Build(); app.MapControllers(); //这一句不要忘了 app.Run();
接着,新建一个类,或者在“新建项”中选择空的 API 控制器。
[Route("api/[controller]")] [ApiController] public class Demo : ControllerBase { …… }
Route 特性指定访问这个控制器的 URL,[controller] 是个占位符,访问时用实际的控制器名来替换。比如,这里的控制器的名字是 Demo,访问时的URL就是 http://somehost/api/demo/xxxx。不过,这里老周的命名不太规范,规范的命名应该是 DemoController。只是老周嫌它的后缀太长。
其实 API 和 MVC 的控制器实现起来一样,但 API 没有视图,所以类继承时,基类可以用 ControllerBase 类而不是 Controller 类。另外,在类上面加一个 ApiController 特性,表明这个 Demo 类是作为 API 控制器用的,并且它的派生类都作为 API 控制器。
好,我们先实现两个 Action。
[Route("getbt")] [HttpGet] public string GetWTF() => "What the bitch"; [Route("getak")] [HttpGet] public IDictionary<string, int> GetAK() { // 返回一个类实例和返回字典对象 // 其JSON结构差不多 // 此处为了简单,直接用字典 return new Dictionary<string, int> { ["item1"] = 10, ["item2"] = 49 }; }
Action 方法上指定的 Route 是相对于控制器类的 Route 的,即 /api/demo/getbt、/api/demo/getak。
这个相信各位看得懂,不用过多解释,看不懂的肯定是因为你太谦虚了。
运行一下这个示例,直接通过浏览器的开发人员工具查看,得知:
第一个 action 返回的 string 类型,因此默认选用 text/plain 格式(普通文本)。
第二个 action 返回的是字典对象,默认选择 application/json 格式。
现在,把 Produces 特性用上,使其返回的数据变为 text/json 格式。
[Route("api/[controller]")] [ApiController] [Produces("text/json")] public class Demo : ControllerBase { …… }
再次运行,从浏览器的开发人员工具中查看HTTP消息。
不过,你得小心!如果你指定的格式与 API 所返回的对象无法兼容,就会崩盘。比如,把上面的 getak 改成这样:
[Route("getak")] [HttpGet] [Produces("text/plain")] public IDictionary<string, int> GetAK() { …… }
虽然 Demo 控制器类上应用了 Produces 特性指定了 text/json 格式,但这个方法上也应用了此特性,依据就近原则,程序会优先选用 text/plain 格式。在内部的处理机制中,这是不匹配的,除非方法的返回值类型是 string。
一旦执行,就会得到错误状态码。

下面演示一个返回 jpg 图像格式(即 image/jpeg)的例子。在刚才的 Demo 控制器类上增加一个方法,名为 GetImage。
[Route("getpic")] [HttpGet] [Produces("image/jpeg")] public Stream GetImage() { // 因为应用程序目录和内容目录相同 // 所以直接获取Current即可 string dirpath = Directory.GetCurrentDirectory(); // 直接返回文件流 return System.IO.File.OpenRead(Path.Combine(dirpath, "505.jpg")); }
方法的返回类型为 Stream 对象,套用 image/jpeg 格式是没问题的,毕竟图像是以二进制的方式响应的。
老周事先从网上找了一张图片,命名为 505.jpg,放在项目根目录下。你在测试时可以随便找个图片,或者拍一张妹子的照片(前提是妹子不会报警),放到项目目录下即可,文件名自己改。
在浏览器中访问后得到结果如下图所示。

--------------------------------------------------- 异次元分界线 -----------------------------------------------------------
既然数据可以以 JSON 格式返回,那能不能返回 XML 格式呢?当然是可以的。
public class 帅哥 { public string Name { get; set; } public int Age { get; set; } public decimal Weight { get; set; } }
----------------------------------------------------------- [Route("getxml")] [HttpGet] [Produces("application/xml")] public 帅哥 GetXML() { return new 帅哥 { Name = "老周", Age = 93, Weight = 203.77M }; }
先是定义了一个新类,叫“帅哥”,接着,GetXML 方法返回一个“帅哥”类型的实例。注意此方法应用了 Produces 特性,指定返回的数据格式为 application/xml。
Web API 控制器默认是不启用 XML 输出支持的,所以在 Program.cs 文件中,在注册MVC功能到服务容器时,需要手动开启对XML输出的支持。
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers().AddXmlSerializerFormatters(); var app = builder.Build(); ……
这样一来,访问 /api/demo/getxml 就能得到 XML 数据了。

好了,今天的文章就水到这里了,下一篇咱们聊聊 FormatFilter 特性类。
Recommend
-
15
2-Acre Vertical Farm Run By AI And Robots Out-Produces 720-Acre Flat Farm by Andrea D. SteffenDecember 23, 2020 Share
-
3
今天又要给大家介绍一个 Spring Boot 中的组件–HandlerMethodReturnValueHandler。 在前面的文章中(如何优雅的实现 Spring Boot 接口参数加密解密?),松哥已经和大家介绍过如何对...
-
9
Study: Social media contributes to a more diverse news diet — wait, what?! Are filter bubbles a myth?...
-
3
July 20, 2021 ...
-
5
String.slice! produces a strange result advertisements The following produces a strange result for slice! (unless I have made a mistake)....
-
14
Swift-DocC Swift-DocC is a documentation compiler for Swift frameworks and packages aimed at making it easy to write and publish great developer documentation. For an example of Swift-DocC in action, check out
-
9
Sustainable EnergyGoldman and VW-backed Northvolt produces battery cell with recycled nickel, manganese and cobaltPublished Fri, Nov 12 2021...
-
4
在上一篇烂文中老周已向各位介绍过 Produces 特性的使用,本文老周将介绍另一个特性类:FormatFilterAttribute。 这个特性算得上是筛选器的马甲,除了从 Attribute 类派生外,还实现了 IFilterFactory 接口。之所以说它是个马甲,是因...
-
4
Oct 6, 2021 ginWrapper v1.0: 统一响应格式 经历过前(web, 客户端,嵌入式,etc)后端联调的同学都知道,指定规范的交互协议是非常重要的。如果没有一定的规范,协议的格式必然是五花八门...
-
4
保证应用不因 Core Data 的原因导致意外崩溃是对开发者的起码要求。本文将介绍可能在视图中产生严重错误的原因,如何避免,以及在保证视图对数据变化实时响应的前提下如何为使用者提供更好、更准确的信息。由于本文会涉及大量前文中介绍的技巧和方法,因此最好一并阅...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK