在Newtonsoft.Json中反序列化自定义异常 [英] Deserializing custom exceptions in Newtonsoft.Json

查看:80
本文介绍了在Newtonsoft.Json中反序列化自定义异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Newtonsoft.Json 11.0.2版中反序列化自定义异常时遇到了麻烦.在Newtonsoft.Json版本10.0.3中,它可以正常工作.

I've been having trouble deserializing custom exceptions in Newtonsoft.Json version 11.0.2. It works fine in Newtonsoft.Json version 10.0.3.

我使用-序列化和反序列化

I serialize and deserialize using -

result = JsonConvert.SerializeObject( <<object of type MyHttpException>> );
MyHttpException deserializedException = JsonConvert.DeserializeObject<MyHttpException>(result);

反序列化期间出现的错误是Newtonsoft.Json.JsonSerializationException:

The error I get during deserialization is a Newtonsoft.Json.JsonSerializationException:

找不到用于MyHttpException类型的构造函数. 一个类应该具有一个默认的构造函数,一个带有参数的构造函数或一个标有JsonConstructor属性的构造函数. 路径"HttpStatusCode",第2行,位置19.

Unable to find a constructor to use for type MyHttpException. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path 'HttpStatusCode', line 2, position 19.

如果将无参数构造函数添加到MyHttpException和MyBaseException,则不会获得任何异常.但是InnerException不会反序列化,并且为null.

If I add a parameterless constructor to MyHttpException and MyBaseException, I don't get any exception. But the InnerException is not deserialized and is null.

我明显缺少什么吗?我不确定为什么它会在10.0.3中工作并在11.0.2中中断.

Is there something obvious I'm missing? I'm not sure why this would work in 10.0.3 and break in 11.0.2.

我的异常类–

public sealed class MyHttpException : MyBaseException
{
    public MyHttpException(HttpStatusCode httpStatusCode, int MyStatusCode)
        : base(MyStatusCode) => HttpStatusCode = httpStatusCode;

    public MyHttpException(HttpStatusCode httpStatusCode, int MyStatusCode, string message)
        : base(MyStatusCode, message) => HttpStatusCode = httpStatusCode;

    public MyHttpException(HttpStatusCode httpStatusCode, int MyStatusCode, Exception innerException)
        : base(MyStatusCode, innerException) => HttpStatusCode = httpStatusCode;

    public MyHttpException(HttpStatusCode httpStatusCode, int MyStatusCode, string message, Exception innerException)
        : base(MyStatusCode, message, innerException) => HttpStatusCode = httpStatusCode;

    [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
    private MyHttpException(SerializationInfo info, StreamingContext context)
        : base(info, context) => HttpStatusCode = (HttpStatusCode)info.GetValue("HttpStatusCode", typeof(HttpStatusCode));

    public HttpStatusCode HttpStatusCode { get; set; }

    [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        if (info == null)
        {
            throw new ArgumentNullException("info");
        }

        info.AddValue("HttpStatusCode", HttpStatusCode);

        // MUST call through to the base class to let it save its own state
        base.GetObjectData(info, context);
    }
}

public abstract class MyBaseException : Exception
{
    public MyBaseException(int MyStatusCode) => this.MyStatusCode = MyStatusCode;

    public MyBaseException(int MyStatusCode, string message)
        : base(message) => this.MyStatusCode = MyStatusCode;

    public MyBaseException(int MyStatusCode, Exception innerException)
        : base("MyErrorCode: " + MyStatusCode + ". " + MyStatusCodes.GetDescription(MyStatusCode) + ". " + innerException.Message, innerException) => this.MyStatusCode = MyStatusCode;

    public MyBaseException(int MyStatusCode, string message, Exception innerException)
        : base(message, innerException) => this.MyStatusCode = MyStatusCode;

    [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
    protected MyBaseException(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
        MyStatusCode = info.GetInt32("MyStatusCode");
    }

    public int MyStatusCode { get; set; }

    [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        if (info == null)
        {
            throw new ArgumentNullException("info");
        }

        info.AddValue("MyStatusCode", MyStatusCode);

        // MUST call through to the base class to let it save its own state
        base.GetObjectData(info, context);
    }
}

谢谢

推荐答案

在Json.NET 11中,对ISerializable类型的序列化方式进行了更改.根据发行说明:

In Json.NET 11 a change was made to how ISerializable types are serialized. According to the release notes:

  • 更改-实现ISerializable但不具有[SerializableAttribute]的类型不会使用ISerializable进行序列化
  • Change - Types that implement ISerializable but don't have [SerializableAttribute] are not serialized using ISerializable

因此,您现在必须使用 SerializableAttribute :

Thus you must now mark your exception types with SerializableAttribute:

[Serializable]
public sealed class MyHttpException : MyBaseException
{
}

[Serializable]
public abstract class MyBaseException : Exception
{
}

或者,您可以创建一个自定义合同解析器来还原旧的行为:

Alternatively, you could create a custom contract resolver that restores the old behavior:

public class PreferISerializableContractResolver : DefaultContractResolver
{
    protected override JsonContract CreateContract(Type objectType)
    {
        var contract = base.CreateContract(objectType);

        if (!IgnoreSerializableInterface
            && contract is JsonObjectContract
            && typeof(ISerializable).IsAssignableFrom(objectType)
            && !objectType.GetCustomAttributes(true).OfType<JsonContainerAttribute>().Any())
        {
            contract = CreateISerializableContract(objectType);
        }

        return contract;
    }
}

(您可能要缓存合同解析器以获得最佳性能.)

为什么要进行此更改?根据问题#1622:派生自System.Exception的类无法正确地序列化/反序列化:

Why was this change made? According to Issue #1622: classes deriving from System.Exception do not serialize/deserialize properly:

Json.NET先前版本未正确序列化ISerializable类型. SerializableAttribute是必需的.

Json.NET previous wasn't serializing ISerializable types correctly. The SerializableAttribute is required.

有关更多信息,请参见此处 dotnet/corefx#23415 .

See here for more info dotnet/corefx#23415.

依次是链接的问题 dotnet/corefx问题#23415:尝试序列化DirectoryInfo时出现PlatformNotSupportedException Newtonsoft.Json 的实例表明更改是应.NET Core团队的要求进行的:

And in turn the linked issue dotnet/corefx Issue #23415: PlatformNotSupportedException when attempting to serialize DirectoryInfo instance with Newtonsoft.Json indicates that the change was made at the request of the .NET Core team:

JamesNK 于2017年8月29日发表评论

JamesNK commented on Aug 29, 2017

所以问题在于Json.NET正在检查一种类型是否实现了ISerializable,但还没有在检查SerialiazableAttribute?

So the issue is Json.NET is checking that a type implements ISerializable but not also checking for the SerialiazableAttribute?

ViktorHofer 于2017年8月29日发表评论

ViktorHofer commented on Aug 29, 2017

正确:)

因此,如果您确实使用PreferISerializableContractResolver而不是用[Serializable]标记ISerializable类型,则在.NET Core中可能会遇到此问题.

Thus if you do use PreferISerializableContractResolver instead of marking your ISerializable types with [Serializable], you might encounter this very issue in .NET Core.

这篇关于在Newtonsoft.Json中反序列化自定义异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆