【问题标题】:JSON.NET: How deserialize specific Exception typeJSON.NET:如何反序列化特定的异常类型
【发布时间】:2020-07-20 22:07:23
【问题描述】:

考虑以下非常简单的代码。

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}");

瞧……内部异常类型是Exception,而不是NullReferenceException。 所以我搜索了 SO 并找到了很多用于反序列化的自定义 JsonConverter 示例(因为序列化的 JSON 包含 ClassName 属性,可用于创建特定类型)。所以我写了一个(为简单起见,仅出现ReadJson,其余照常)。

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

并在调用上述DeserializeObject 函数时传递此转换器。 这一次,我得到了异常:

Newtonsoft.Json.JsonSerializationException:无法将 JSON 对象填充到类型“System.Exception”上。路径“类名”

据我研究 Newtonsoft.Json 代码,似乎“问题”是 Exception[Serializable]ISerializable 所以它使用不支持填充对象的 SerializableContract。但是在这里我以绝望告终:-(。有人可以帮助我吗?

(上面的例子只是为了简单起见,我需要对自己的异常进行序列化和反序列化,这些异常要复杂得多。使用的是Newtonsoft.Json 11.0.0.2版本。)

【问题讨论】:

    标签: c# json.net json-deserialization


    【解决方案1】:

    您忘记了 TypeNameHandling 设置。[Typehandling] 所以请像下面这样修复你的代码,它会正常工作

    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}");
    

    【讨论】:

    • 谢谢。有用。但是......如果我无法更改序列化过程(例如它发生在无法访问的服务器上),所以我得到没有TypeNameHandling 的 json?有什么办法可以处理这种行为?我在序列化的json中还有“ClassName”项,所以可以找到目标类型,但是不知道如何将信息传递给反序列化过程。
    • 如果您没有任何机会更改您操作的 json,那么您所能做的就是编写自定义活页夹或 customserializer :)
    • CustomeBinder 没有任何意义,因为它不包含任何上下文,而 CustomSerializer?你的意思是CustomConverter?这就是我在问题中尝试过的......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 2013-12-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多