5

Consider the following very simple code.

var ex_to_serialize = new Exception("something wrong", new NullReferenceException("set to null"));
var serialized_ex = JsonConvert.SerializeObject(ex_to_serialize);

var deserialized_ex = JsonConvert.DeserializeObject<Exception>(serialized_ex);
Console.WriteLine($"Type of inner exception: {deserialized_ex.InnerException.GetType().Name}");

And voilá... the inner exception type is Exception instead of NullReferenceException. So I searched SO and find lot of example with custom JsonConverter used for desrialization (as the serialized JSON contains ClassName property, which could be used to create the specific type). So I wrote one (only ReadJson is present for simplicity, rest is as usual).

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    if (reader.TokenType == JsonToken.Null)
        return null;
    var json_object = Newtonsoft.Json.Linq.JObject.Load(reader);
    var target_type_name = json_object.Value<string>("ClassName");
    var target_type = Type.GetType(target_type_name);
    var target = Activator.CreateInstance(target_type);
    serializer.Populate(json_object.CreateReader(), target);
    return target;
}

And pass this converter when calling DeserializeObject function above. This time, I get exception:

Newtonsoft.Json.JsonSerializationException: Cannot populate JSON object onto type 'System.Exception'. Path 'ClassName'

As far as I dug into the Newtonsoft.Json code, it seems the "problem" is that Exception is [Serializable] and ISerializable so it uses SerializableContract which does not support populating object. But here I end in desperation :-(. Could someone help me?

(The example above is just for simplicity, I need to serialize and deserialize my own exceptions, which are far more complex. Newtonsoft.Json version 11.0.0.2 used.)

1 Answer 1

5

You are forgetting TypeNameHandling setting.[Typehandling] So please fix your code like the following, it will work properly

var ex_to_serialize = new Exception("something wrong", new NullReferenceException("set to null"));

var serialized_ex = JsonConvert.SerializeObject(ex_to_serialize,new JsonSerializerSettings{TypeNameHandling = TypeNameHandling.All});

var deserialized_ex = JsonConvert.DeserializeObject<Exception>(serialized_ex, new JsonSerializerSettings{TypeNameHandling = TypeNameHandling.All});

Console.WriteLine($"Type of inner exception: {deserialized_ex.InnerException.GetType().Name}");
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks. It works. But... what in the case I cannot change the serialization process (e.g. it happens on the unaccessible server), so I get json without TypeNameHandling? Is there any way how to handle the behaviour? I still have the item "ClassName" in the serialized json, so I can find the target type, but I do not know how to pass the information to the deserialization process.
If you you have no whatsoever chance to change the json you manipulate then all you can do is either write a custom binder or customserializer :)
CustomeBinder has no sense, because it doesn't contains any context, and CustomSerializer? You mean the CustomConverter? That's what I tried in the question...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.