【WebAPI No.5】Core WebAPI中的自定义格式化
分类:
IT文章
•
2025-01-03 21:01:37
介绍
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 类型:
ActionResult<T>。ActionResult类型表示多种的HTTP状态码。属于此类别的一些常见返回类型包括:
(400)
(404)
(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> 类型:
IActionResult 类型可提供以下优势:
- 属性
-
return T,什么个意思哪,说白了就是在定义的时候指定了类型直接return就可以了。
返回响应补充:
我就写部分常用的其他的有兴趣可以去官网了解一下:返回状态相应
自定义格式化程序
我们都知道WebAPI因为MVC的内置所以默认支持了json,xml和文本格式。那么我们想使用其他格式怎么办哪,微软总是不会让我们失望,我们可以自定义啊。
首先创建自定义格式化程序大致步骤:
- 从相应的基类中派生类。
- 在构造函数中指定有效的媒体类型和编码。
- 方法
- 方法
从相应的基类中派生:
从那些类中派生官方给的解释是;
基类派生。
对于二进制类型,从 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
类型创建 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
以下示例中突出显示的行展示了如何从依赖关系注入容器中获取服务(不能从构造函数参数中获取它们)
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