使用TypeNameHandling.All
反序列化列表时,如果缺少其中一个项目的类型命名空间(序列化后删除),则会导致Error resolving type specified in JSON
错误。
我希望忽略这些项目,留下其余部分。
Error = (sender, args) => { args.ErrorContext.Handled = true; }
中的{p> JsonSerializerSettings
执行我正在寻找的内容,但当然会捕获所有错误。
有没有更简洁的方法,可能是通过我错过的序列化设置?
答案 0 :(得分:3)
您可以在ErrorContext
中使用SerializationErrorCallback
的以下属性来限制要处理和忽略的错误类型:
ErrorEventArgs.ErrorContext.OriginalObject
:此获取导致错误的原始对象。当由于类型名称无效而无法构建列表项时,OriginalObject
将是列表本身。
使用此属性,您可以查看某些OriginalObject
IList<T>
是否为T
。
ErrorEventArgs.CurrentObject
。获取引发错误事件的当前对象。异常冒泡序列化调用堆栈,每个级别的对象都可以尝试处理错误。
您需要在最低级别处理CurrentObject == ErrorContext.OriginalObject
。
ErrorEventArgs.ErrorContext.Error
- 获取实际的异常抛出。您只想处理serialization binder抛出的异常。
现在,如何仅检测和捕获由于类型名称绑定失败而导致的异常?事实证明,当无法加载类型时,Json.NET的DefaultSerializationBinder
会抛出JsonSerializationException
。但是,在许多其他情况下可能会抛出相同的异常,包括格式错误的JSON文件。因此,引入一个包装器SerializationBinder
,它捕获并捕获JSON绑定器中的异常并将它们打包成特定的异常类型:
public class JsonSerializationBinder : SerializationBinder
{
readonly SerializationBinder binder;
public JsonSerializationBinder(SerializationBinder binder)
{
if (binder == null)
throw new ArgumentNullException();
this.binder = binder;
}
public override Type BindToType(string assemblyName, string typeName)
{
try
{
return binder.BindToType(assemblyName, typeName);
}
catch (Exception ex)
{
throw new JsonSerializationBinderException(ex.Message, ex);
}
}
public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
binder.BindToName(serializedType, out assemblyName, out typeName);
}
}
public class JsonSerializationBinderException : JsonSerializationException
{
public JsonSerializationBinderException()
{
}
public JsonSerializationBinderException(string message)
: base(message)
{
}
public JsonSerializationBinderException(string message, Exception innerException)
: base(message, innerException)
{
}
public JsonSerializationBinderException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
此外,在代码中的某个更高级别,Json.NET将JsonSerializationBinderException
打包到另一个JsonSerializationException
中,因此有必要查看必要的异常的内部异常类型。因此,以下设置应该完成这项工作:
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
Binder = new JsonSerializationBinder(new DefaultSerializationBinder()),
Error = (sender, args) =>
{
if (args.CurrentObject == args.ErrorContext.OriginalObject
&& args.ErrorContext.Error.InnerExceptionsAndSelf().OfType<JsonSerializationBinderException>().Any()
&& args.ErrorContext.OriginalObject.GetType().GetInterfaces().Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IList<>)))
{
args.ErrorContext.Handled = true;
}
}
};
使用扩展方法:
public static class ExceptionExtensions
{
public static IEnumerable<Exception> InnerExceptionsAndSelf(this Exception ex)
{
while (ex != null)
{
yield return ex;
ex = ex.InnerException;
}
}
}
示例fiddle。