System.Text.Json - 反序列化可以是空字符串或 class 的对象

System.Text.Json - Deserialize object that can be either an empty string or a class

我正在使用 System.Text.Json 反序列化一些 json。 (更具体地说,this call 来自 Last.fm API json 格式)

我试图反序列化的 json 有一种非常规的方式来处理某些对象的空值,例如当它为空时我得到这个:

    "tags": "",

当它有值时像这样:

    "tags": {
        "tag": [
            {
                "name": "classic rock",
                "url": "https://www.last.fm/tag/classic+rock"
            },
            {
                "name": "rock",
                "url": "https://www.last.fm/tag/rock"
            }
        ]
    }

我的 C# class 看起来像这样:

public class Artist
{
    public Tags Tags { get; set; }
}

public class Tags
{
    public Tag[] Tag { get; set; }
}

public class Tag
{
    public string Name { get; set; }
    public string Url { get; set; }
}

在实际尝试反序列化之前如何检查对象是否为空字符串?

当我尝试反序列化它时:

var deserializedObject = JsonSerializer.Deserialize<T>(requestBody);

它抛出 System.Text.Json.JsonException: The JSON value could not be converted to FMBot.LastFM.Domain.Models.Tags. Path: $.artist.tags 错误。

这个调用曾经在值实际为 null 时起作用,但现在它是一个空字符串,它被破坏了,我无法找到解决方案。

解决此问题的一个简单方法是将 Tags 属性 的类型更改为 dynamic

public class Artist
{
    public dynamic Tags { get; set; }
}

然后您可以检查 Tags is Tag[]Tags is string 并采取相应措施。别忘了检查它是否不是以上两者(并且可能会抛出)。

我会为此任务使用自定义转换器。例如:

public class TagsConverter : JsonConverter<Tags>
{
    public override Tags Read(ref Utf8JsonReader reader, Type typeToConvert, 
        JsonSerializerOptions options)
    {
        // If the token is a string, return null
        if(reader.TokenType == JsonTokenType.String)
        {
            return null;
        }

        // Skip over the object and property name
        reader.Read(); // Object
        reader.Read(); // Property name

        // Read the tags array
        var tags = JsonSerializer.Deserialize<Tag[]>(ref reader, options);

        reader.Read(); // Object

        return new Tags { Tag = tags};
    }

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

并像这样使用它:

var options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true,
    Converters = { new TagsConverter() }
};

var deserializedObject = JsonSerializer.Deserialize<Artist>(requestBody, options );