gpt4 book ai didi

c# - 在 Newtonsoft.Json 中反序列化自定义异常

转载 作者:行者123 更新时间:2023-11-30 15:16:00 30 4
gpt4 key购买 nike

我在反序列化 Newtonsoft.Json 版本 11.0.2 中的自定义异常时遇到了问题。它在 Newtonsoft.Json 版本 10.0.3 中运行良好。

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

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

我在反序列化期间遇到的错误是 Newtonsoft.Json.JsonSerializationException:

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。

有什么明显的我遗漏的东西吗?我不确定为什么这会在 10.0.3 中工作并在 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 类型的序列化方式发生了变化。根据release notes :

  • Change - Types that implement ISerializable but don't have [SerializableAttribute] are not serialized using ISerializable

因此,您现在必须用 SerializableAttribute 标记您的异常类型:

[Serializable]
public sealed class MyHttpException : MyBaseException
{
}

[Serializable]
public abstract class MyBaseException : Exception
{
}

或者,您可以创建一个 custom contract resolver恢复旧行为:

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

(您可能想要 cache the contract resolver for best performance 。)

为什么要进行此更改?根据Issue #1622: classes deriving from System.Exception do not serialize/deserialize properly :

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

See here for more info dotnet/corefx#23415.

然后是链接问题 dotnet/corefx Issue #23415: PlatformNotSupportedException when attempting to serialize DirectoryInfo instance with Newtonsoft.Json表示更改是应 .NET Core 团队的要求进行的:

JamesNK commented on Aug 29, 2017

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

ViktorHofer commented on Aug 29, 2017

Correct :)

因此,如果您使用 PreferISerializableContractResolver 而不是使用 [Serializable] 标记您的 ISerializable 类型,您可能会在 .NET 中遇到这个问题核心。

关于c# - 在 Newtonsoft.Json 中反序列化自定义异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50845255/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com