在Newtonsoft.Json中反序列化自定义异常 [英] Deserializing custom exceptions in 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. TheSerializableAttribute
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屋!