【问题标题】:JSON.NET is ignoring properties in types derived from System.Exception. Why?JSON.NET 忽略派生自 System.Exception 的类型中的属性。为什么?
【发布时间】:2014-11-28 23:47:58
【问题描述】:

我想对继承 System.Exception 的自定义异常对象进行 JSON 序列化。 JsonConvert.SerializeObject 似乎忽略了派生类型的属性。这个问题可以很简单地说明:

class MyException : Exception {
    public string MyProperty { get; set; }
}

class Program {
    static void Main(string[] args) {
        Console.WriteLine(JsonConvert.SerializeObject(new MyException {MyProperty = "foobar"}, Formatting.Indented));
        //MyProperty is absent from the output. Why?
        Console.ReadLine();
    }
}

我尝试在正确的位置添加 DataContract 和 DataMember 属性。他们没有帮助。我该如何让它发挥作用?

【问题讨论】:

  • ExceptionISerializable。尝试覆盖它。
  • 我找到了与 Thomas 相同的解决方案。扩展 ISerializable 实现比忽略它要好。考虑一下,ISerializable 是由基类的创建者实现的,这是有原因的。忽略它会绕过他们的所有工作。当我将 IgnoreSerializableInterface 与我的异常一起使用时,不包括 ClassName 属性。结果,我以后无法对其进行反序列化。扩展 GetObjectData 和构造函数可以完美运行。 (我会将此作为评论,但我还没有声誉。)

标签: c# json serialization json.net


【解决方案1】:

因为 Exception 实现了ISerializable,Json.Net 默认使用它来序列化对象。您可以告诉它忽略ISerializable,如下所示:

var settings = new JsonSerializerSettings() {
    Formatting = Formatting.Indented,
    ContractResolver = new DefaultContractResolver() { 
        IgnoreSerializableInterface = true 
    } 
};
Console.WriteLine(JsonConvert.SerializeObject(new MyException {MyProperty = "foobar"}, settings));

【讨论】:

  • 这会导致错误,因为异常有自引用成员。除了代码之外,您还必须在 JsonSerializerSettings 中指定 ReferenceLoopHandling = ReferenceLoopHandling.Ignore。无论如何,我认为以这种方式序列化异常是一个非常糟糕的主意,因为 TargetSite 属性可以生成一个非常重的字符串(比如几个 MBytes)。
  • @MaximeRossini,你是对的。但是可以使用DynamicContractResolver 来忽略TargetSite 属性。
  • @MaximeRossini 仅供参考,TargetSite 在按照this PR 进行序列化时不再包含
【解决方案2】:

您还可以通过覆盖GetObjectData 方法和ctor(SerializationInfo, StreamingContext) 将特定对象添加和检索到System.Runtime.Serialization.SerializationInfo 存储区:

public class MyCustomException : Exception
{
    public string MyCustomData { get; set; }

    protected MyCustomException (SerializationInfo info, StreamingContext context) : base(info, context)
    {
        MyCustomData = info.GetString("MyCustomData");
    }

    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
        info.AddValue("MyCustomData", MyCustomData);
    }
}

这样MyCustomObject 属性将被包含在序列化和反序列化中。

【讨论】:

  • 除此之外,我还需要将[Serializable] 属性添加到派生异常类中才能正常工作
猜你喜欢
  • 2012-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-13
  • 1970-01-01
  • 1970-01-01
  • 2014-03-31
  • 2018-12-11
相关资源
最近更新 更多