在 .NET Core 3 中序列化 Manatee.Json



>背景
我想从我的 .NET Core 3 应用程序中提供一些 JsonSchema,以及序列化为 JSON 的其他对象。由于Manatee.Json经常更新并为JsonSchema提供良好的支持,因此它们是我的首选。同时,.NET Core 3 为返回具有魔力的对象提供了出色的支持,这些对象将它们转换为 JSON 文档。

例:

public ActionResult<MyFancyClass> MyFancyAction()
{
return new MyFancyClass {
Property1 = "property 1 content",
Property2 = "property 2 content",
};
}

输出:

{
"Property1": "property 1 content",
"Property2": "property 2 content"
}


Problem.NET Core 3 具有对 JSON 及其System.Text.Json的内部支持,该支持在前面的示例中使用。如果我尝试序列化Manatee.Json.Schema.JsonSchema,则其内部结构是序列化的,而不是json架构本身。

例:

public ActionResult<MyFancyClass2> MyFancyAction2()
{
return new MyFancyClass2 {
Property1 = "property 1 content",
Property1Schema = new JsonSchema()
.Type(JsonSchemaType.String)
};
}

输出:

{
"Property1": "property 1 content",
"Property1Schema": [{
"name":"type",
"supportedVersions":15,
"validationSequence":1,
"vocabulary": {
"id":"https://json-schema.org/draft/2019-09/vocab/validation",
"metaSchemaId":"https://json-schema.org/draft/2019-09/meta/validation"
}
}]
}

我期望这个:

{
"Property1": "property 1 content",
"Property1Schema": {
"type": "string",
}
}

Manatee.Json.JsonValue还有一个冲突的内部结构,其中System.Text.Json.JsonSerializer无法正确访问内部 get 方法,例如我收到以下异常消息:

Cannot access value of type Object as type Boolean.

发现
Manatee.Json.Schema.JsonSchema有一个.ToJson()方法,可用于获取正确的 json 架构作为JsonValue,但随后我遇到了我刚刚提到的序列化Manatee.Json.JsonValue的问题。

问题
有谁知道使System.Text.Json能够序列化Manatee.Json结构的方法?

Sidemark
另一种方法是完全替换System.Text.Json(看看这个问题(。

.NET Core 3 json 序列化附带了许多配置选项。其中之一是添加指定应如何序列化不同类型的转换器。一种前进的方法是为JsonSchema创建一个JsonConverter,为JsonValue创建一个。

对于JsonSchema,我们可以实现一个JsonSchemaConverter,在序列化/写入时,将 json 模式提取为 JsonValue,并要求序列化程序序列化该 JsonValue。喜欢这个:

public class JsonSchemaConverter : JsonConverter<JsonSchema>
{
public JsonSchemaConverter()
{
_manateeSerializer = new ManateeSerializer();
}
private ManateeSerializer _manateeSerializer { get; set; }
public override JsonSchema Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var jsonText = reader.GetString();
var jsonValue = JsonValue.Parse(jsonText);
return _manateeSerializer.Deserialize<JsonSchema>(jsonValue);
}
public override void Write(Utf8JsonWriter writer, JsonSchema value, JsonSerializerOptions options)
{
var schemaAsJson = value.ToJson(_manateeSerializer);
try
{
System.Text.Json.JsonSerializer.Serialize<JsonValue>(writer, schemaAsJson, options);
}
catch (Exception e)
{
Log.Information($"Failed to serialize JsonSchema ({e.Message});");
writer.WriteNullValue();
}
}
}

对于JsonValue我们可以将其更改为System.Text.Json理解的东西,因为它毕竟是 json。一种不幸的方法是将JsonValue序列化为string,例如解析它JsonDocument.Parse(string)并序列化其RootElement属性。感觉没有必要通过JsonDocument,所以如果有人找到更好的解决方案,那就太好了! 可能的实现可能如下所示:

public class JsonValueConverter : JsonConverter<JsonValue>
{
public override JsonValue Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var json = reader.GetString();
return JsonValue.Parse(json);
}
public override void Write(Utf8JsonWriter writer, JsonValue value, JsonSerializerOptions options)
{
string content = value.ToString();
try
{
var jsonDocument = JsonDocument.Parse(content);
JsonSerializer.Serialize<JsonElement>(writer, jsonDocument.RootElement, options);
}
catch (Exception e)
{
Log.Warning($"JsonDocument.Parse(JsonValue) failed in JsonValueConverter.Write(,,).n{e.Message}");
writer.WriteNullValue();
}
}
}

他们必须在以下Startup.cs注册:

public void ConfigureServices(IServiceCollection services)
{
services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new JsonValueConverter());
options.JsonSerializerOptions.Converters.Add(new JsonSchemaConverter());
});
}

最新更新