简体   繁体   中英

Deserialize dynamic structure with Newtonsoft Json

I'm getting some problems trying to deserialize a "dynamic" JSON structure in my application.

I'm receiving a json object which have a field, packages , that can be valorized as an array of strings or as an array of "objects". So, in some situation I have something like this:

"packages" : [ "Test", "Var" ]

and somethimes I have:

"packages" : [ {
    "id" : "9",
    "name" : "Test"
},
{
    "id" : "19",
    "name" : "Opt"
}]

In my domain class I tried to define the packages field this way:

public List<object> packages { get; set; }

But this seems to work only when I'm deserializing array of strings. When I'm getting objects, instead, the packages field in my class is valorized as null .

How can I solve this issue? Can I avoid deserialization just for the packages fileld and get the value as a simple string?

NOTE : I also tried to define the field like this:

public String packages { get; set; }

but I'm getting an exception...

You can use JToken to replace object

public class [YourClassName]
{
    public List<JToken> packages { get; set; }
}

then you can yourObject.packages.First().ToString()

The problem is that you are trying to deserialize 2 different input types into 1, which is not something C# likes. The return type of the Json Parser must be well defined, meaning it's not possible to have a List that sometimes has a String , and sometimes some Object .

I think the correct way to handle this is to firstly find out what your input looks like, by for instance using some Regex expression. After you find out what the input looks like, use the Json parser to parse the input to an object that fits your input.

For a list of strings use:

class ParsedStrings {
    public List<String> Packages { get; set; }
}

For a list of objects use:

   class ParsedObjects {
        public List<IdName> Names { get; set; }

        public class IdName {
             public string Id { get; set; }
             public string Name { get; set; }
        }
   }

Since you're using a strongly typed language, this input is not really well formed. You should think about either using a different language to match your problem, or changing your input to better fit your environment.

I finally solved implementing a custom JsonConverter :

public class PackagesConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;

        List<string> res = new List<string>();

        var jsonArray = JArray.Load(reader);
        foreach (var i in jsonArray)
        {
            if (i.Count() > 1)
            {
                var name = i["name"];
                res.Add(name.ToString());
            }
            else
            {
                res.Add(i.ToString());

            }
        }
        return res;
    }

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

And applying it to my field:

[JsonConverter(typeof(PackagesConverter))]
public List<String> packages { get; set; }

This is working fine...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM