使用 newtonsoft 反序列化 JSON Object/Array 时出错

Error Deserializing JSON Object/Array using newtonsoft

我有一个 json 字符串,其中包含以下数据

"air:FlightOptionsList": {
    "air:FlightOption": [{
            "LegRef": "hx5kk+3R2BKABGzqAAAAAA==",
            "Destination": "LHE",
            "Origin": "DXB",
            "air:Option": {
                "Key": "hx5kk+3R2BKA/FzqAAAAAA==",
                "TravelTime": "P0DT3H0M0S",
                "air:BookingInfo": {
                    "BookingCode": "I",
                    "BookingCount": "7",
                    "CabinClass": "Economy",
                    "FareInfoRef": "hx5kk+3R2BKAzFzqAAAAAA==",
                    "SegmentRef": "hx5kk+3R2BKAtFzqAAAAAA=="
                }
            }
        }, {
            "LegRef": "hx5kk+3R2BKAFGzqAAAAAA==",
            "Destination": "DXB",
            "Origin": "LHE",
            "air:Option": {
                "Key": "hx5kk+3R2BKACGzqAAAAAA==",
                "TravelTime": "P0DT11H30M0S",
                "air:BookingInfo": [{
                        "BookingCode": "U",
                        "BookingCount": "7",
                        "CabinClass": "Economy",
                        "FareInfoRef": "hx5kk+3R2BKA+FzqAAAAAA==",
                        "SegmentRef": "hx5kk+3R2BKAvFzqAAAAAA=="
                    }, {
                        "BookingCode": "Y",
                        "BookingCount": "9",
                        "CabinClass": "Economy",
                        "FareInfoRef": "hx5kk+3R2BKA+FzqAAAAAA==",
                        "SegmentRef": "hx5kk+3R2BKAxFzqAAAAAA=="
                    }
                ],
                "air:Connection": {
                    "SegmentIndex": "0"
                }
            }
        }
    ]
}

我的Class结构如下:

public class FlightOptionsList
{
    public List<FlightOption> FlightOption { get; set; }
}

public class FlightOption
{
    public string LegRef { get; set; }
    public string Destination { get; set; }
    public string Origin { get; set; }
    public Option Option { get; set; }
}

public class Option
{
    public string Key { get; set; }
    public string TravelTime { get; set; }
    public List<BookingInfo> BookingInfo { get; set; }
    public Connection Connection { get; set; }
}

public class BookingInfo
{
    public string BookingCode { get; set; }
    public string BookingCount { get; set; }
    public string CabinClass { get; set; }
    public string FareInfoRef { get; set; }
    public string SegmentRef { get; set; }
}

我想反序列化它,但它给我一个错误如下:

无法将当前 JSON 对象(例如 {"name":"value"})反序列化为类型 'System.Collections.Generic.List`1[ParseSoapEnveloperReqRes.BookingInfo]',因为该类型需要 JSON 数组(例如 [1,2,3])以正确反序列化。 要修复此错误,请将 JSON 更改为 JSON 数组(例如 [1,2,3])或更改反序列化类型,使其成为普通的 .NET 类型(例如,不是原始类型像整数,而不是像数组或列表这样的集合类型),可以从 JSON 对象反序列化。 JsonObjectAttribute 也可以添加到类型以强制它从 JSON 对象反序列化。 路径 'FlightOptionsList.FlightOption[0].Option.BookingInfo.BookingCode',第 394 行,位置 59。

这是因为,就像您看到 json 字符串一样,FlightOptionsList.FlightOption[0].Option.BookingInfo 是一个 object 但在 FlightOptionsList.FlightOption[1].Option.BookingInfo 中是一个 array,如您所见。

如何设置这个问题...我正在使用以下代码将 json 字符串反序列化为 class 对象

 var AirTravelResultModel = JsonConvert.DeserializeObject<AirTravelResultModel>(xmlInputData);

查看 Camilo Martinez 对此讨论的回答: Deserializing JSON when sometimes array and sometimes object

基本上,您需要将 JsonConverter 属性添加到 BookingInfo 属性 并在 JsonConverter 实现中处理转换。

public class FlightOptionsList
{
    public List<FlightOption> FlightOption { get; set; }
}

public class FlightOption
{
    public string LegRef { get; set; }
    public string Destination { get; set; }
    public string Origin { get; set; }
    public Option Option { get; set; }
}

public class Option
{
    public string Key { get; set; }
    public string TravelTime { get; set; }
    [JsonConverter(typeof(SingleValueArrayConverter<BookingInfo>))]
    public List<BookingInfo> BookingInfo { get; set; }
    public Connection Connection { get; set; }
}

public class BookingInfo
{
    public string BookingCode { get; set; }
    public string BookingCount { get; set; }
    public string CabinClass { get; set; }
    public string FareInfoRef { get; set; }
    public string SegmentRef { get; set; }
}

public class Connection
{
    public string SegmentIndex { get; set; }
}

这是转换器:

public class SingleValueArrayConverter<T> : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        object retVal = new Object();
        if (reader.TokenType == JsonToken.StartObject)
        {
            T instance = (T)serializer.Deserialize(reader, typeof(T));
            retVal = new List<T>() { instance };
        }
        else if (reader.TokenType == JsonToken.StartArray)
        {
            retVal = serializer.Deserialize(reader, objectType);
        }
        return retVal;
    }

    public override bool CanConvert(Type objectType)
    {
        return true;
    }
}

此答案中的大部分文字是您问题中的文字,并进行了一些调整。你需要做的就是修复你的 JSON 结构,并用 JsonProperty 属性装饰 classes 因为你的 JSON 属性 名字有 air:: 在 C# 中是不允许的。就这些了。

步骤 1

您需要做的第一件事是修复您的 JSON,因为在一种情况下 air:BookingInfo 是一个对象,而在另一种情况下,它是一个数组。因此,它的模式是不一致的。正确的 JSON 应该是这样的:

{
    "air:FlightOption": [{
            "LegRef": "hx5kk+3R2BKABGzqAAAAAA==",
            "Destination": "LHE",
            "Origin": "DXB",
            "air:Option": {
                "Key": "hx5kk+3R2BKA/FzqAAAAAA==",
                "TravelTime": "P0DT3H0M0S",
                "air:BookingInfo": [{
                    "BookingCode": "I",
                    "BookingCount": "7",
                    "CabinClass": "Economy",
                    "FareInfoRef": "hx5kk+3R2BKAzFzqAAAAAA==",
                    "SegmentRef": "hx5kk+3R2BKAtFzqAAAAAA=="
                }]
            }
        },
        {
            "LegRef": "hx5kk+3R2BKAFGzqAAAAAA==",
            "Destination": "DXB",
            "Origin": "LHE",
            "air:Option": {
                "Key": "hx5kk+3R2BKACGzqAAAAAA==",
                "TravelTime": "P0DT11H30M0S",
                "air:BookingInfo": [{
                        "BookingCode": "U",
                        "BookingCount": "7",
                        "CabinClass": "Economy",
                        "FareInfoRef": "hx5kk+3R2BKA+FzqAAAAAA==",
                        "SegmentRef": "hx5kk+3R2BKAvFzqAAAAAA=="
                    },
                    {
                        "BookingCode": "Y",
                        "BookingCount": "9",
                        "CabinClass": "Economy",
                        "FareInfoRef": "hx5kk+3R2BKA+FzqAAAAAA==",
                        "SegmentRef": "hx5kk+3R2BKAxFzqAAAAAA=="
                    }
                ],
                "air:Connection": {
                    "SegmentIndex": "0"
                }
            }
        }
    ]
}

步骤 2

您可以使用 Visual Studio 轻松地为您的 JSON 创建 classes,正如我在此 .

中所示

步骤 3

您需要稍微帮助序列化程序并告诉它如何将 JSON 属性映射到您的 class 的属性,为此您可以使用 JsonPropertyAttribute 属性作为如下所示:

public class FlightOptionsList
{
    [JsonProperty("air:FlightOption")]
    public AirFlightoption[] airFlightOption { get; set; }
}

public class AirFlightoption
{
    public string LegRef { get; set; }
    public string Destination { get; set; }
    public string Origin { get; set; }
    [JsonProperty("air:Option")]
    public AirOption airOption { get; set; }
}

public class AirOption
{
    public string Key { get; set; }
    public string TravelTime { get; set; }
    [JsonProperty("air:BookingInfo")]
    public AirBookingInfo[] airBookingInfo { get; set; }
    [JsonProperty("air:Connection")]
    public AirConnection airConnection { get; set; }
}

public class AirBookingInfo
{
    public string BookingCode { get; set; }
    public string BookingCount { get; set; }
    public string CabinClass { get; set; }
    public string FareInfoRef { get; set; }
    public string SegmentRef { get; set; }
}

public class AirConnection
{
    public string SegmentIndex { get; set; }
}

步骤 4

您唯一需要的代码是:

var fol = JsonConvert.DeserializeObject<FlightOptionsList>("YourJSON");

对于发布两次的冗余,我深表歉意......不幸的是,这个问题在其前身中得到了一定程度的解决:Deserializing JSON when sometimes array and sometimes object。我不会使用你的对象。确保您的对象格式正确。有时公司可能会将对象存储为数组或对象,具体取决于是一个还是多个。您可能 运行 喜欢它。确保您的转换器正在 return 正在等待您的对象类型的列表或数组。在我的例子中,我需要 return 一个数组。

阐述 Martinez 和 mfanto 对 Newtonsoft 的回答。他们的答案确实适用于 Newtonsoft:

这是一个使用数组而不是列表(并且命名正确)的示例。

public class SingleValueArrayConverter<T> : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartObject 
            || reader.TokenType == JsonToken.String
            || reader.TokenType == JsonToken.Integer)
        {
            return new T[] { serializer.Deserialize<T>(reader) };
        }
        return serializer.Deserialize<T[]>(reader);
    }

    public override bool CanConvert(Type objectType)
    {
        return true;
    }
}

然后在属性上写这个:

[JsonProperty("INSURANCE")]
[JsonConverter(typeof(SingleValueArrayConverter<InsuranceInfo>))]
public InsuranceInfo[] InsuranceInfo { get; set; }

Newtonsoft 将为您完成剩下的工作。

return JsonConvert.DeserializeObject<T>(json);

为 Martinez 和 mfanto 干杯!

信不信由你,这将适用于子项目。 (它甚至可能必须。)所以...在我的 InsuranceInfo 中,如果我有另一个 object/array 混合动力车,请在 属性 上再次使用它,如下所示:

[JsonProperty("CLAIM")]
[JsonConverter(typeof(SingleValueArrayConverter<Claim>))]
public Claim[] ClaimInfo { get; set; }

由于实现了 WriteJson,这也将允许在必要时将对象重新序列化回 json,但在这一点上,它将始终是一个数组(耶!)。