在反序列化列表期间忽略缺少的类型

时间:2016-09-08 05:21:30

标签: c# json serialization json.net

使用TypeNameHandling.All反序列化列表时,如果缺少其中一个项目的类型命名空间(序列化后删除),则会导致Error resolving type specified in JSON错误。
我希望忽略这些项目,留下其余部分。

Error = (sender, args) => { args.ErrorContext.Handled = true; }中的{p> JsonSerializerSettings执行我正在寻找的内容,但当然会捕获所有错误。

有没有更简洁的方法,可能是通过我错过的序列化设置?

1 个答案:

答案 0 :(得分:3)

您可以在ErrorContext中使用SerializationErrorCallback的以下属性来限制要处理和忽略的错误类型:

现在,如何仅检测和捕获由于类型名称绑定失败而导致的异常?事实证明,当无法加载类型时,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