简体   繁体   中英

Json.net deserialization issue when target is an abstract object

I'm using a service which returns a json .

I have a key-value object where the key is a string and the value is an object and I know where to cast the object based on the key.

It will look something like:

{
  "key1": "This is key 1",
  "key2": 12,
  "key3": ["Key 3 first item", "Key 3 second item"]
}

With simple types (eg) strings , long , int etc. There is no problem.
My problem starts when I receive an array (key3).

My c# code will look something like this:

Dictionary<string, object> values = GetValuesFromTheService();
string str = (string)values["key1"]; // Ok
long lng = (long)values["key2"]; // Ok
List<string> strs = (List<string>)values["key3"]; // BAD

key3 is actually a JArray and not a List<string> - I guess this happens since I'm using an object as a value and not being more specific (a List<object> will also be better then a JArray ).

Is there anything I can do about this?

You should be able to parse the entire object to a jObject and then select the keys back out to the types you need. This is untested but the basic idea.

var j = JObject.Parse(GetValuesFromTheService());
string str = (string)j.SelectToken("key1");
long lng = (long)j.SelectToken("key2");
var strs = (List<string>)j.SelectToken("key3");

I have a similar situation when attempting to (de)serialize some of our custom enumerations. For the solution, I created a custom JsonConvertor. Here's the code I use for that...

public class EnumerationConverter : JsonConverter
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var enm = (Enumeration)value;
            writer.WriteValue(enm.Value);
        }

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

            int value;

            if (reader.ValueType == typeof(Int64))
            {
                value = Convert.ToInt32(reader.Value);
            }
            else
            {
                value = (int)reader.Value;
            }

            return Enumeration.FromValueOrDefault(objectType, value);

        }

        public override bool CanConvert(Type objectType)
        {
            if (objectType.BaseType == null) return false;
            return objectType.BaseType.Name == "Enumeration";
        }
    }

Then, when I want to invoke it and pull the json back into my object, here's the line for that one...

JsonConvert.DeserializeObject<List<CustomObjectDto>>(req.Content.ReadAsStringAsync().Result, new EnumerationConverter());

Nice thing is that this becomes universally available and the CustomObjectDto can just have an instance of this magic dictionary in it as a property...or even multiple...and will apply the conversion on only the properties that match according to the logic in the convertor...hope that helps.

And here's a link to a similar topic --> http://blog.maskalik.com/asp-net/json-net-implement-custom-serialization/

如果key3string值的JArray ,则可以执行以下操作:

List<string> strs = ((JArray)values["key3"]).Select(t => t.Value<string>()).ToList();

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