C# десериализация JSON массива, однозначных и многозначных результатов - PullRequest
1 голос
/ 12 марта 2020

Я пытаюсь десериализовать структуру, которая содержит один элемент с несколькими элементами в нем, который, в свою очередь, может содержать один или несколько элементов внутри ... Вот пример JSON:

"Content": {
    "title": {
        "$type": "EntityModelData",
        "Id": "1133",
        "Content": {
            "intro": "Example Introduction",
            "title": "Example Title",
        }
    },
    "sections": {
        "$type": "ContentModelData[]",
        "$values": [
            {
                "title": {
                    "$type": "EntityModelData",
                    "Id": "1232",
                    "Content": {
                        "title": "Section 1 (Single-value context)"
                    }
                },
                "context": {
                    "$type": "ContentModelData",
                    "publicationType": {
                        "$type": "KeywordModelData",
                        "Id": "1175",
                    }
                }
            },
            {
                "title": {
                    "$type": "EntityModelData",
                    "Id": "1234",
                    "Content": {
                        "title": "Section 2 (Multi-valued context)"
                    }
                },
                "context": {
                    "$type": "ContentModelData[]",
                    "$values": [
                        {
                            "publicationType": {
                                "$type": "KeywordModelData",
                                "Id": "1182",
                            },
                            "contentType": {
                                "$type": "KeywordModelData",
                                "Id": "1166",
                            }
                        },
                        {
                            "publicationType": {
                                "$type": "KeywordModelData",
                                "Id": "1182",
                            },
                            "contentType": {
                                "$type": "KeywordModelData",
                                "Id": "1238",
                            }
                        }
                    ]
                }
            }
        ]
    }
}

Я настроил свои классы следующим образом ...

public class ContentModel
{
    [JsonProperty("Content")]
    public Content Content { get; set; }
}

public class Content
{
    [JsonProperty("title")]
    public TitleModel Title { get; set; }

    [JsonProperty("sections")]
    public List<Sections> Sections { get; set; }
}

//[JsonArrayAttribute("sections")] (Putting this in makes it fail!)
public class Sections
{
    [JsonProperty("title")]
    public TitleModel Title { get; set; }

    //[JsonProperty("context")]
    //public Context Context { get; set; }

    //[JsonProperty("context")]
    //public IList<Context> Contexts { get; set; }
}

public class Context
{
    //[JsonProperty("$type")]
    //public string Type { get; set; }

    //[JsonProperty("publicationType")]
    //public Keyword PublicationType { get; set; }

    //[JsonProperty("contentType")]
    //public Keyword ContentType { get; set; }

    //[JsonProperty("subject")]
    //public Keyword Subject { get; set; }
}

Обратите внимание, что некоторые из них закомментированы, так как они ломаются, когда я включаю или пытаюсь дополнительно десериализовать элементы context (single / multi )

Команда десериализации, которую я использую: ...

var pageContent = JObject.Parse([[above-content-that has a lot more in it]]);
foreach (var entity in pageContent.SelectToken(".Parent[0].ContanerForContent[[which has the above JSON it it]]"))
{
    var content = entity.ToObject<ContentModel>().Content; break;
}

Теперь эта операция успешно десериализована до заголовка !!! (с комментариями, которые у меня есть выше в коде) ... Я могу l oop через список «разделов» и попасть в их «Заголовок» ... но когда я пытаюсь включить контекст (который является одновременно однозначные и многозначные ... выдает ошибку ниже ...

1.

List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Path 'Regions[0].Entities[1].Content.sections.$values[2].context.$values', line 1, position 5038.'

2.

List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Path 'Regions[0].Entities[1].Content.sections.$values', line 1, position 4214.'

3.

Newtonsoft.Json.JsonSerializationException: 
'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[Context]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.

To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type 
(e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.

Path 'Regions[0].Entities[1].Content.guidebookSections.$values[0].context.publicationType', line 1, position 4271.'

Я пробовал несколько разных способов, но продолжаю получать вариации ошибки на разных уровнях.

На данный момент - я думаю, что я полностью ошибаюсь. Я десериализирую элементы "context"?

1 Ответ

1 голос
/ 13 марта 2020

Спасибо за данные выше ... все они были образовательными, и в конце концов я нашел тот, который работал для меня ...

public class SingleValueArrayConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);

        if (jo["$type"].Value<string>().Contains("[]"))
        {
            return jo.ToObject<List<T>>(serializer);
        }
        else
        {
            return new List<T>(new[] { jo.ToObject<T>(serializer) });
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

, а затем в моих свойствах, где я мог получить любой список или один элемент ... Я добавляю это:

[JsonProperty("context")]
[JsonConverter(typeof(SingleValueArrayConverter<Context>))]
public List<Context> Context { get; set; }
...