JSON.NET忽略从System.Exception派生的类型中的属性。为什么?

17
我想将继承自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属性了,但是它们没有起到帮助作用。我该如何让这个工作?


1
“Exception” 是 “ISerializable”。尝试覆盖它。 - Lucas Trzesniewski
我发现了和Thomas一样的解决方案。扩展ISerializable实现比忽略它要好。请考虑,基类的创建者之所以实现了ISerializable是有原因的。忽略它会绕过他们所有的工作。当我在我的异常中使用IgnoreSerializableInterface时,ClassName属性没有被包含。结果,我无法在以后对其进行反序列化。扩展GetObjectData和构造函数完美地解决了这个问题。(我本来想把这个留作评论的,但我还没有声望。) - Jack Whipnert
2个回答

19

由于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));

4
这将导致错误,因为异常具有自引用成员。 除了您的代码之外,还必须在“JsonSerializerSettings”中指定“ReferenceLoopHandling = ReferenceLoopHandling.Ignore”。无论如何,我认为以这种方式序列化异常是一个非常糟糕的想法,因为“TargetSite”属性可以生成一个非常大(例如几兆字节)的字符串。 - Maxime Rossini
@MaximeRossini,你是对的。但是可以使用DynamicContractResolver来忽略TargetSite属性。 - Ivan Kochurkin
1
@MaximeRossini FYI,根据此PR,在序列化时不再包括TargetSite - pushkin

8

您还可以通过覆盖 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属性将被包含在序列化和反序列化中。

3
除此之外,我需要为派生的异常类添加[Serializable]属性才能使其正常工作。 - dasch88

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接