.NET Core 自定义格式化程序构建(YAML 格式化程序)





0/5 (0投票)
了解如何为 ASP.NET Core 应用程序创建自定义请求/响应格式化程序
引言
不久前,我开始接触 .NET Core 的格式化程序。简而言之,格式化程序的作用是以您偏好的数据格式格式化您的响应和请求。例如,如果使用 Json
格式化程序,它会将您的响应(控制器操作返回的值)和请求(作为参数传递给控制器的值)格式化为 Json。XML 和其他格式化程序也是如此。.NET Core 开箱即用提供了一些格式化程序。 此官方文档 对它们进行了简要介绍。
但我们还是少谈格式化程序,多看看如何创建我们自己的自定义格式化程序吧。我想这正是我们来这里的目的,对吧?是的!让我们开始吧。
因此,框架提供了两个 abstract
类:InputFormmeter
和 OutputFormatter
。基本上,您会想使用这些类来创建自己的格式化程序。但是,还有另外两个 abstract
类扩展自这两个格式化程序。TextInputFormatter
和 TextOuputFormatter
可以处理简单的 string
表示的数据格式的响应(数据也可以是二进制形式)。例如,Json
和 XML
格式化程序就扩展了这些类。我们将构建两个 Yaml
格式化程序,一个用于输入,另一个用于输出格式化。
那么,YAML 是什么呢?这是我直接从维基百科上抓取的定义:
YAML 是一种人类可读的数据序列化语言。它通常用于配置文件,但也可用于许多存储(例如调试输出)或传输(例如文档头)数据的应用程序。YAML 针对与 XML 相同的许多通信应用程序,但采取了更简洁的方法,并且故意打破与 SGML 的兼容性。YAML 是 JSON 的超集,JSON 是另一种简洁的数据序列化格式,它使用缩进而不是大括号和方括号。
这个想法非常简单。在使用 Yaml
输出格式化程序时,您将从当前的 HttpContext
中获取响应(控制器操作的返回值),将其 Serialize
为原始 Yaml
响应文本,然后将其发送回客户端。输入格式化程序也基本相同。在这种情况下,您将 Deserialize
来自客户端请求的 Yaml
内容,并以通用形式使用它们。另一件重要的事情是,您必须为这些格式化程序显式设置媒体类型头。这样做将在客户端定义具有该特定媒体类型格式(application/x-yaml
)的 Accept
头(用于输出)和 Content-Type
(用于输入)时激活这些格式化程序。
如果您不想在调用控制器操作时使用这些头,可以在获取或发布内容时显式定义应使用的格式化程序类型。例如,[Produces(application/x-yaml)]
将以 Yaml
格式返回响应,无论您是否定义了 Accept
头。同样,使用 [Consumes(application/x-yaml)]
属性将仅接受 Yaml
内容,无论您是否定义了 Content-Type
。
历史课就到这里。下面是 Yaml
的输入格式化程序。顺便说一下,我正在使用 Antoine Aubry(@antoineaubry)的 YamlDotNet 库进行 Yaml 的序列化和反序列化过程。
YamlInputFormatter.cs
public class YamlInputFormatter : TextInputFormatter
{
private readonly Deserializer _deserializer;
public YamlInputFormatter(Deserializer deserializer)
{
_deserializer = deserializer;
SupportedEncodings.Add(Encoding.UTF8);
SupportedEncodings.Add(Encoding.Unicode);
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationYaml);
SupportedMediaTypes.Add(MediaTypeHeaderValues.TextYaml);
}
public override Task<InputFormatterResult> ReadRequestBodyAsync
(InputFormatterContext context, Encoding encoding)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (encoding == null)
{
throw new ArgumentNullException(nameof(encoding));
}
var request = context.HttpContext.Request;
using (var streamReader = context.ReaderFactory(request.Body, encoding))
{
var type = context.ModelType;
try
{
var model = _deserializer.Deserialize(streamReader, type);
return InputFormatterResult.SuccessAsync(model);
}
catch (Exception)
{
return InputFormatterResult.FailureAsync();
}
}
}
}
代码基本上是自 explanatory 的。从请求正文中获取 Yaml
内容,然后将其反序列化为通用类型,您就完成了。
这是 YamlOutputFormatter.cs
public class YamlOutputFormatter : TextOutputFormatter
{
private readonly Serializer _serializer;
public YamlOutputFormatter(Serializer serializer)
{
_serializer = serializer;
SupportedEncodings.Add(Encoding.UTF8);
SupportedEncodings.Add(Encoding.Unicode);
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationYaml);
SupportedMediaTypes.Add(MediaTypeHeaderValues.TextYaml);
}
public override async Task WriteResponseBodyAsync
(OutputFormatterWriteContext context, Encoding selectedEncoding)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (selectedEncoding == null)
{
throw new ArgumentNullException(nameof(selectedEncoding));
}
var response = context.HttpContext.Response;
using (var writer = context.WriterFactory(response.Body, selectedEncoding))
{
WriteObject(writer, context.Object);
await writer.FlushAsync();
}
}
private void WriteObject(TextWriter writer, object value)
{
if (writer == null)
{
throw new ArgumentNullException(nameof(writer));
}
_serializer.Serialize(writer, value);
}
}
如果您想知道 MediaTypeHeaderValues
是从哪里来的?这是一个简单的类,我在其中为我的应用程序设置了所有媒体类型头。
internal class MediaTypeHeaderValues
{
public static readonly MediaTypeHeaderValue ApplicationYaml
= MediaTypeHeaderValue.Parse("application/x-yaml").CopyAsReadOnly();
public static readonly MediaTypeHeaderValue TextYaml
= MediaTypeHeaderValue.Parse("text/yaml").CopyAsReadOnly();
}
请注意,YamlInputFormatter
的构造函数接受一个 Deserializer
,而 YamlOutputFormatter
的构造函数接受一个 Serializer
。我们在 Startup.cs 的 ConfigureServices
方法中配置格式化程序时,会构建带有某些选项的 Serializer
和 Deserializer
。
public void ConfigureServices(IServiceCollection services)
{
// Add framework services
services.AddMvc(options=>
{
options.InputFormatters.Add(new YamlInputFormatter(new DeserializerBuilder().
WithNamingConvention(namingConvention: new CamelCaseNamingConvention()).Build()));
options.OutputFormatters.Add(new YamlOutputFormatter(new SerializerBuilder().
WithNamingConvention(namingConvention: new CamelCaseNamingConvention()).Build()));
options.FormatterMappings.SetMediaTypeMappingForFormat
("yaml", MediaTypeHeaderValues.ApplicationYaml);
});
}
一个简单的 GET
请求,Accept
头设置为 application/x-yaml
一个简单的 POST
请求,Content-Type
头设置为 application/x-yaml
格式化程序映射器是一个很棒的选项,在从浏览器客户端调用操作并指定格式时非常有用。例如,设置 [HttpGet("/api/[controller].{format}")]
属性将以浏览器 URL 中定义的格式返回操作结果。
[FormatFilter]
[HttpGet]
[HttpGet("/api/[controller].{format}")]
public IEnumerable<Geek> Get()
{
return new List<Geek>()
{
new Geek() { Id = 1, Name = "Fiyaz", Expertise="Javascript", Rating = 3.0M },
new Geek() { Id = 2, Name = "Rick", Expertise = ".Net", Rating = 5.0M }
};
}
您可以像这样调用操作:http://appurl/geeks.yaml 以 Yaml
格式获取响应,或者像这样调用:http://appurl/geeks.json 以 Json
格式获取响应。
就是这样!这就是我关于构建 .NET Core 自定义格式化程序的所有知识。如果您愿意,可以在网络上找到其他社区成员提供的许多其他格式化程序,或者自己构建。我在 GitHub 仓库中提供的解决方案中添加了另外两个输出格式化程序。一个是 Pdf,另一个是 Xlsx 格式。 这是仓库的链接。
历史
- 2017 年 3 月 22 日:初版