【问题标题】:Serializing Manatee.Json in .NET Core 3在 .NET Core 3 中序列化 Manatee.Json
【发布时间】:2020-05-08 08:32:34
【问题描述】:

背景
我想从我的 .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"
}

问题
.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(看看 this question)。

【问题讨论】:

    标签: json .net-core .net-core-3.0 system.text.json manatee.json


    【解决方案1】:

    .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());
            });
    }
    

    【讨论】:

      猜你喜欢
      • 2020-05-08
      • 1970-01-01
      • 1970-01-01
      • 2020-01-26
      • 2020-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多