我在实现 REST API 的 ASP.NET Core (.NET 8) 项目中使用 Newtonsoft JSON.NET 进行对象序列化,并且我需要从其他地方使用的序列化设置更改用于 Swagger 示例的序列化设置,但我没有看到任何方法仅为 Swagger UI 自定义序列化设置。可以吗?如果可以的话,有没有例子?
这是我正在寻找的背景信息和一些细节。
我们使用 JSON.NET,因为它在处理我们无法控制的数据时更加宽容。例如,我们可以在其中一项外部服务中返回错误详细信息,并在字符串属性中嵌入非转义换行符,这违反了 JSON 规范。这不是我们的代码,因此我们无法修复它,并且 Microsoft 的 JSON 序列化无法处理它,而 JSON.NET 可以。所以,我们现在必须使用它。
当我们为 JSON 配置 MVC 设置时,我们使用以下选项:
builder.Services
.AddControllers()
.AddNewtonsoftJson
(
options =>
{
options.SerializerSettings.Converters.Add(new StringEnumConverter());
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
options.SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
// Do not change the following line or it may fail to serialize hierarchical data.
options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
}
);
这工作得很好,只是当 Swagger UI 显示预期传递给 POST/PATCH 方法的输入对象的示例时,这些对象包含
$id
属性,这会让读者感到困惑。例如,如果我有一个像这样的对象:
public class GroupRequestCreateExample: IExamplesProvider<Group>
{
public Group GetExamples()
{
Group group = new()
{
DisplayName = "Fonzie Fans",
Description = "Everyone who likes Fonzie."
};
return group;
}
}
Swagger 示例将显示为:
{
"$id":"1",
"displayName":"Fonzie Fans",
"description": "Everyone who likes Fonzie."
}
我希望它看起来像:
{
"displayName":"Fonzie Fans",
"description": "Everyone who likes Fonzie."
}
我了解如何在全局范围内关闭显示
$id
属性,但如果这样做,它会中断从外部服务接收分层数据的调用,因此我需要为除 Swagger 示例之外的所有内容保留 options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects
设置。
可以吗?
您可以自定义
ISchemaFilter
,例如如下所示:
public class CustomSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (context.Type == typeof(Group))
{
var groupExample = new GroupRequestCreateExample().GetExamples();
// Customize the JSON serialization settings here
var settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
DateFormatHandling = DateFormatHandling.IsoDateFormat,
PreserveReferencesHandling = PreserveReferencesHandling.None
};
var exampleJson = JsonConvert.SerializeObject(groupExample, settings);
schema.Example = new OpenApiString(exampleJson);
}
}
}