ASP.NET Core Web API 中的自定义格式化程序Custom formatters in ASP.NET Core Web API

ASP.NET Core MVC 使用输入和输出格式化程序支持 Web API 中的数据交换。模型绑定使用输入格式化程序。使用输出格式化程序。

该框架为 JSON 和 XML 提供内置的输入和输出格式化程序。它为纯文本提供内置的输出格式化程序,但不为纯文本提供输入格式化程序。

本文展示如何通过创建自定义格式化程序,添加对其他格式的支持。有关纯文本的自定义输入格式化程序的示例,请参阅 GitHub 上的 TextPlainInputFormatter

如何下载

如果希望过程支持内置格式化程序所不支持的内容类型,可使用自定义格式化程序。

例如,如果 Web API 的某些客户端可以处理 Protobuf 格式,你可能想在这些客户端上使用 Protobuf,因为它更高效。或者,你可能希望 Web API 使用 格式发送联系人姓名和地址,这种格式经常用于交换联系人数据。本文提供的示例应用可实现简单的 vCard 格式化程序。

创建和使用自定义格式化程序的步骤如下:

  • 如果想对要发送到客户端的数据进行序列化,则创建输出格式化程序类。
  • 如果想对从客户端接收的数据进行反序列化,则创建输入格式化程序类。
  • 将格式化程序的实例添加到 MvcOptionsOutputFormatters 中的 集合。

以下部分针对其中每个步骤提供了指南和代码示例。

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

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

有关输入格式化程序示例,请参阅。

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

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

  1. public VcardOutputFormatter()
  2. {
  3. SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/vcard"));
  4. SupportedEncodings.Add(Encoding.Unicode);
  5. }

有关输入格式化程序示例,请参阅示例应用

备注

不能在格式化程序类中执行构造函数依赖关系注入。例如,不能通过向构造函数添加记录器参数来获取记录器。若要访问服务,必须使用传递到方法的上下文对象。的代码示例展示了如何执行此操作。

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

CanWriteResult 方法The CanWriteResult method

在某些情况下,必须重写 CanWriteResult,而不是 CanWriteType如果满足以下条件,则使用 CanWriteResult

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

例如,假设操作方法签名返回 Person 类型,但它可能返回从 Student 派生的 InstructorPerson 类型。如果希望格式化程序仅处理 对象,请检查提供给 对象CanWriteResult类型。请注意,当操作方法返回 CanWriteResult 时,不必使用 IActionResult;在这种情况下,CanWriteType 方法可接收运行时类型。

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

  1. public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
  2. {
  3. IServiceProvider serviceProvider = context.HttpContext.RequestServices;
  4. var logger = serviceProvider.GetService(typeof(ILogger<VcardOutputFormatter>)) as ILogger;
  5. var response = context.HttpContext.Response;
  6. var buffer = new StringBuilder();
  7. if (context.Object is IEnumerable<Contact>)
  8. {
  9. foreach (Contact contact in context.Object as IEnumerable<Contact>)
  10. {
  11. FormatVcard(buffer, contact, logger);
  12. }
  13. }
  14. else
  15. {
  16. }
  17. await response.WriteAsync(buffer.ToString());
  18. }
  19. private static void FormatVcard(StringBuilder buffer, Contact contact, ILogger logger)
  20. {
  21. buffer.AppendLine("BEGIN:VCARD");
  22. buffer.AppendLine("VERSION:2.1");
  23. buffer.AppendFormat($"N:{contact.LastName};{contact.FirstName}\r\n");
  24. buffer.AppendFormat($"FN:{contact.FirstName} {contact.LastName}\r\n");
  25. buffer.AppendFormat($"UID:{contact.ID}\r\n");
  26. buffer.AppendLine("END:VCARD");
  27. logger.LogInformation("Writing {FirstName} {LastName}", contact.FirstName, contact.LastName);
  28. }

有关输入格式化程序示例,请参阅。

若要使用自定义格式化程序,请将格式化程序类的实例添加到 InputFormattersOutputFormatters 集合。

按格式化程序的插入顺序对其进行计算。第一个优先。

  • 此文档的示例应用,它可实现简单的 vCard 输入和输出格式化程序。该应用可读取和写入与以下示例类似的 vCard:
  1. BEGIN:VCARD
  2. VERSION:2.1
  3. N:Davolio;Nancy
  4. FN:Nancy Davolio
  5. UID:20293482-9240-4d68-b475-325df4a83728
  6. END:VCARD

若要查看 vCard 输出,请运行该应用程序,并向 (从 Visual Studio 运行时)或 http://localhost:5000/api/contacts/(从命令行运行时)发送具有 Accept 标头“text/vcard”的 Get 请求。