细聊ASP.NET Core WebAPI格式化程序
内容提要
本文介绍了ASP.NET Core WebAPI中的格式化程序,包括输入格式化程序和输出格式化程序。输入格式化程序负责将请求数据转换为具体类型对象,输出格式化程序负责将对象转换为指定格式的数据。通过自定义YAML格式的转换器和内置的JSON和XML格式化程序的源码分析,了解了它们的工作原理和使用方法。同时,还介绍了模型绑定和ObjectResult的执行过程中如何选择合适的格式化程序。阅读和理解源码可以更好地掌握和使用格式化程序。
延伸解读
格式化程序的作用范围
文章指出,InputFormatter和OutputFormatter仅对Controller/Action中返回ObjectResult的情况生效,Minimal API和gRPC等不适用。这意味着在传统WebAPI中,格式化程序是控制请求和响应数据格式的核心机制,但在其他编程模型下需要采用不同的方式处理数据格式。
自定义格式化程序的注册与依赖注入
通过MvcOptions直接添加格式化程序实例无法使用依赖注入的服务。文章提供了扩展IConfigureOptions<MvcOptions>的解决方案,通过YamlMvcOptionsSetup类在Configure方法中利用DI容器创建格式化程序实例,再注册到容器中,从而解决依赖注入问题。
输出格式化程序的选择逻辑
DefaultOutputFormatterSelector根据请求的Accept头和ObjectResult的ContentTypes属性选择输出格式化程序。如果Accept头为空,则选择第一个满足条件的格式化程序;如果ObjectResult设置了ContentTypes,则优先匹配这些类型。重写CanWriteResult方法可以防止格式化程序被默认选中,确保只有符合特定条件时才使用。
源码阅读的价值
文章强调阅读源码能深入理解格式化程序的工作原理,解决实际问题。通过分析TextInputFormatter和TextOutputFormatter的模板方法模式,以及BodyModelBinder和ObjectResultExecutor的调用流程,可以更好地掌握格式化程序的扩展和定制,提升开发水平。
Q&A
ASP.NET Core WebAPI中的输入格式化程序和输出格式化程序分别有什么作用?
输入格式化程序(InputFormatter)负责将请求数据转换为具体类型对象,输出格式化程序(OutputFormatter)负责将对象转换为指定格式的数据。
如何自定义一个YAML格式的输入格式化程序?
创建一个继承自TextInputFormatter的类,在构造函数中添加SupportedMediaTypes(如text/yaml和text/yml)和SupportedEncodings,并重写ReadRequestBodyAsync方法,使用YamlDotNet的IDeserializer将请求体反序列化为对象。最后在MvcOptions中通过options.InputFormatters.Add添加该格式化程序。
在ASP.NET Core WebAPI中,模型绑定是如何选择并使用输入格式化程序的?
模型绑定通过BodyModelBinderProvider获取BodyModelBinder,BodyModelBinder遍历所有IInputFormatter实例,调用其CanRead方法根据请求的Content-Type筛选出匹配的格式化程序,然后调用其ReadAsync方法将请求内容转换为模型对象,并绑定到Action参数上。
ObjectResultExecutor是如何选择输出格式化程序的?
ObjectResultExecutor通过OutputFormatterSelector的SelectFormatter方法选择输出格式化程序。选择时会考虑请求的Accept头、ObjectResult的ContentTypes属性以及格式化程序的CanWriteResult方法。如果Accept头存在且ObjectResult设置了ContentTypes,则优先匹配两者;否则根据Accept头或默认规则选择。
为什么在自定义输出格式化程序时需要重写CanWriteResult方法?
重写CanWriteResult方法可以添加自定义的验证逻辑,防止输出格式化程序被默认选中。例如,在YamlOutputFormatter中,通过检查请求的Accept头是否包含支持的媒体类型(如text/yaml或text/yml)来决定是否使用该格式化程序,从而避免在不匹配的情况下被错误选用。
如何通过依赖注入的方式注册自定义格式化程序?
可以实现IConfigureOptions<MvcOptions>接口,在Configure方法中通过依赖注入获取所需服务(如ILoggerFactory),然后向MvcOptions的InputFormatters和OutputFormatters添加自定义格式化程序实例。最后使用TryAddEnumerable将IConfigureOptions<MvcOptions>的实现注册到DI容器中。