System.Text.Json - десериализовать объект, который может быть пустой строкой или классом.

Я использую System.Text.Json для десериализации некоторых файлов json. (В частности, этот вызов из 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 # выглядит так:

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, но теперь, когда это пустая строка, она не работает, и я не могу найти решение.


person Thom    schedule 19.05.2021    source источник
comment
Плохой тон для публичного API - так кардинально меняться - позор last.fm. При этом вам нужно будет написать JsonConverter для явной обработки этого случая. См. docs.microsoft. com / en-us / dotnet / standard / serialization /   -  person Chris Pickford    schedule 19.05.2021


Ответы (2)


Я бы использовал специальный конвертер для этой задачи. Например:

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 );
person DavidG    schedule 19.05.2021

Один простой способ решить эту проблему - изменить тип свойства Tags на dynamic.

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

Затем вы можете проверить, Tags is Tag[] или Tags is string, и действовать соответственно. Не забудьте также проверить, не соответствует ли он ни одному из вышеперечисленных (и, возможно, бросить).

person BlokeTech    schedule 19.05.2021
comment
Пожалуйста, нет, каждый раз, когда вы используете dynamic, умирает котенок. - person DavidG; 19.05.2021