我在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
:
无法找到用于MyHttpException类型的构造函数。 一个类应该有一个默认的构造函数,一个带参数的构造函数或一个用JsonConstructor属性标记的构造函数。 Path&#39; HttpStatusCode&#39;,第2行,第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);
}
}
由于
答案 0 :(得分:4)
在Json.NET 11中,对ISerializable
类型的序列化方式进行了更改。根据{{3}}:
- 更改 - 实现ISerializable但没有[SerializableAttribute]的类型未使用ISerializable序列化
因此,您现在必须使用release notes标记您的例外类型:
[Serializable]
public sealed class MyHttpException : MyBaseException
{
}
[Serializable]
public abstract class MyBaseException : Exception
{
}
或者,您可以创建一个恢复旧行为的SerializableAttribute
:
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;
}
}
(您可能需要custom contract resolver。)
为什么要做出这种改变?根据{{3}}:
Json.NET以前没有正确序列化
ISerializable
类型。SerializableAttribute
是必需的。有关详细信息,请参阅此处cache the contract resolver for best performance。
反过来,链接问题Issue #1622: classes deriving from System.Exception do not serialize/deserialize properly表明更改是应.NET Core团队的要求进行的:
JamesNK 于2017年8月29日发表评论
所以问题是Json.NET正在检查一个类型是否实现ISerializable但是还没有检查SerialiazableAttribute?
ViktorHofer 于2017年8月29日发表评论
正确:)
因此,如果您使用PreferISerializableContractResolver
而不是使用ISerializable
标记[Serializable]
类型,则可能会在.NET Core中遇到此问题。