System.Text.Json:在自定义转换器中获取属性名称

时间:2021-05-23 11:10:00

标签: c# json-deserialization system.text.json asp.net-core-5.0 custom-converter

使用 JsonSerialize.DeserializeAsync 和自定义转换器进行反序列化,例如

public class MyStringJsonConverter : JsonConverter<string>
{
    public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return reader.GetString();
    }

    public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }
}

在这里我会得到 all string 属性,这没什么,但有没有办法检查给定值的属性名称,例如像这样,只处理 Body 属性的位置:

class MyMailContent 
{
    public string Name { get; set; }
    public string Subject { get; set; }
    public string Body { get; set; }
}

public class MyStringJsonConverter : JsonConverter<string>
{
    public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.PropertyName.Equals("Body"))
        {
            var s = reader.GetString();
            //do some process with the string value
            return s;
        }

        return reader.GetString();
    }
}

或者有其他方法可以挑选出给定的属性吗?

注意,我正在寻找使用 System.Text.Json 的解决方案。

2 个答案:

答案 0 :(得分:2)

System.Text.Json 不会在 path 内使用父属性名称,或者更一般地说是当前值的 JsonConverter<T>.Read()。此信息在内部进行跟踪——它在 ReadStack.JsonPath() 中——但 ReadStack 是内部的,永远不会传递给应用程序代码。

但是,如 Registration sample - [JsonConverter] on a property 中所述,您可以使用 JsonConverterAttributeMyStringJsonConverter 直接应用于 public string Body { get; set; }

class MyMailContent 
{
    public string Name { get; set; }
    public string Subject { get; set; }
    [JsonConverter(typeof(MyStringJsonConverter))]
    public string Body { get; set; }
}

这样做后,MyStringJsonConverter.Read().Write() 将只为 MyMailContent.Body 触发。即使您在 JsonSerializerOptions.Converters 中有一些整体 JsonConverter<string>,应用于该属性的转换器也会 take precedence

<块引用>

在序列化或反序列化期间,按以下顺序为每个 JSON 元素选择一个转换器,从最高优先级到最低优先级:

  • [JsonConverter] 应用于属性。
  • 添加到 Converters 集合的转换器。
  • [JsonConverter] 应用于自定义值类型或 POCO。

(请注意,这与 Newtonsoft 部分不同,在 {{3}} 中,应用于类型的转换器取代了设置中的转换器。)

答案 1 :(得分:1)

感谢 Jimi 提供 comment,在他的祝福下,我使用他建议的解决方案发布了一个 wiki 答案,任何有更多贡献的人,请随时提供。

>

在大多数情况下,接受的答案是一个很好的答案,但如果仍然需要按属性名称处理一个或多个特定属性,这是一种方法。

public class MyMailContent
{
    public string Name { get; set; }
    public string Subject { get; set; }
    public string Body { get; set; }
}

public class MyMailContentJsonConverter : JsonConverter<MyMailContent>
{
    public override MyMailContent Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType != JsonTokenType.StartObject)
        {
            throw new JsonException();
        }

        var mailContent = new MyMailContent();

        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndObject)
            {
                return mailContent;
            }

            if (reader.TokenType == JsonTokenType.PropertyName)
            {
                var propertyName = reader.GetString();

                reader.Read();

                switch (propertyName)
                {
                    case "Name":
                        mailContent.Name = reader.GetString();
                        break;

                    case "Subject":
                        mailContent.Subject = reader.GetString();
                        break;

                    case "Body":
                        string body = reader.GetString();
                        //do some process on body here
                        mailContent.Body = body;
                        break;
                }
            }
        }

        throw new JsonException();
    }

    public override void Write(Utf8JsonWriter writer, MyMailContent mailcontent, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }
}

private static JsonSerializerOptions _jsonDeserializeOptions = new()
{
    ReadCommentHandling = JsonCommentHandling.Skip,
    AllowTrailingCommas = true,
    Converters =
    {
        new MyMailContentJsonConverter()
    }
};

然后像这样使用

var jsonstring = JsonSerializer.Serialize(new MyMailContent
{
    Name = "some name",
    Subject = "some subject",
    Body = "some body"
});

var MailContent = JsonSerializer.Deserialize<MyMailContent>(jsonstring, _jsonDeserializeOptions);
相关问题