使用newtonsoft反序列化JSON对象/数组时出错

时间:2017-11-12 13:32:43

标签: c# json serialization json.net json-deserialization

我有一个包含以下数据的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"
                }
            }
        }
    ]
}

我的班级结构如下:

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对象反序列化的数组或List。 JsonObjectAttribute也可以添加到类型中以强制它从JSON对象反序列化。 路径'FlightOptionsList.FlightOption [0] .Option.BookingInfo.BookingCode',第394行,第59位。

这是因为,好像你看到了json字符串,FlightOptionsList.FlightOption [0] .Option。 BookingInfo 是一个对象,但在FlightOptionsList.FlightOption [1]您可以看到.Option。 BookingInfo 是一个数组

如何设置此问题...我使用以下代码将json字符串反序列化为类对象

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

3 个答案:

答案 0 :(得分:5)

请看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;
    }
}

答案 1 :(得分:0)

本回答中的大多数文字都是来自您的问题的文字,并进行了一些调整。您需要做的就是修复您的JSON结构,并使用JsonProperty属性修饰类,因为您的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创建类,如我在此answer中所示。

第3步

您需要稍微帮助序列化程序并告诉它如何将JSON属性映射到您的类的属性,为此您可以使用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");

答案 2 :(得分:0)

我很抱歉重复两次发布...不幸的是,这个问题在其前身Deserializing JSON when sometimes array and sometimes object中得到了解决。我不会使用您的对象。确保您的对象格式正确。有时,公司可能根据一个或多个对象将对象存储为数组或对象。您可能会遇到这种情况。确保您的转换器返回一个挂起对象类型的列表或数组。在我的实例中,我需要返回一个数组。

阐述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内,如果我有另一个对象/数组混合对象,请再次在该属性上使用它,如下所示:

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

由于实现了WriteJson,因此还可以在必要时将对象重新序列化为json,但是到那时,它将始终是一个数组(是!)。