取消JSON.NET流反序列化

时间:2016-04-14 14:30:19

标签: c# json .net-3.5 json.net

我目前正在使用类似的代码对流中的数据进行反序列化。

    public static MyClass Parse(Stream stream)
    {
        var serializer = new JsonSerializer();
        using (var sr = new StreamReader(stream))
        using (var jsonTextReader = new JsonTextReader(sr))
        {
            var result = serializer.Deserialize<MyClass>(jsonTextReader);
            return result;
        }
    }

是否有可能支持用户取消已开始的反序列化,因为这个过程可能需要很长时间才能获得巨大的json文件并减慢连接速度?

2 个答案:

答案 0 :(得分:1)

JsonTextReader不支持开箱即用,但Json.NET可以正确处理(即重新抛出)来自较低级别代码的异常,因此您可以将读者子类化并自己完成:

public class CancellableJsonTextReader : JsonTextReader
{
    protected Func<bool> CheckCancelled { get; set; }

    public CancellableJsonTextReader(TextReader reader, Func<bool> checkCancelled)
        : base(reader)
    {
        this.CheckCancelled = checkCancelled;
    }

    public bool IsCancelled { get; private set; }

    public override bool Read()
    {
        DoCheckCancelled();
        return base.Read();
    }

    public override bool? ReadAsBoolean()
    {
        DoCheckCancelled();
        return base.ReadAsBoolean();
    }

    public override byte[] ReadAsBytes()
    {
        DoCheckCancelled();
        return base.ReadAsBytes();
    }

    public override DateTime? ReadAsDateTime()
    {
        DoCheckCancelled();
        return base.ReadAsDateTime();
    }

    public override DateTimeOffset? ReadAsDateTimeOffset()
    {
        DoCheckCancelled();
        return base.ReadAsDateTimeOffset();
    }

    public override decimal? ReadAsDecimal()
    {
        DoCheckCancelled();
        return base.ReadAsDecimal();
    }

    public override double? ReadAsDouble()
    {
        DoCheckCancelled();
        return base.ReadAsDouble();
    }

    public override int? ReadAsInt32()
    {
        DoCheckCancelled();
        return base.ReadAsInt32();
    }

    public override string ReadAsString()
    {
        DoCheckCancelled();
        return base.ReadAsString();
    }

    private void DoCheckCancelled()
    {
        if (!IsCancelled && CheckCancelled != null)
            IsCancelled = CheckCancelled();
        if (IsCancelled)
        {
            throw new JsonReaderCancelledException();
        }
    }
}

public class JsonReaderCancelledException : JsonReaderException
{
    public JsonReaderCancelledException() { }

    public JsonReaderCancelledException(string message)
        : base(message)
    {
    }

    public JsonReaderCancelledException(string message, Exception innerException)
        : base(message, innerException)
    {
    }

    public JsonReaderCancelledException(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
    }
}

然后使用它:

    public static T Parse<T>(Stream stream, Func<bool> checkCancelled)
    {
        var serializer = new JsonSerializer();
        using (var sr = new StreamReader(stream))
        using (var jsonTextReader = new CancellableJsonTextReader(sr, checkCancelled))
        {
            var result = serializer.Deserialize<T>(jsonTextReader);
            return result;
        }
    }

然后,在更高的代码级别,捕获JsonReaderCancelledException异常。

请注意,如果您的checkCancelled方法正在检查可能在另一个线程中设置的bool标志,则必须将其声明为volatile。请参阅Is it safe to use a boolean flag to stop a thread from running in C#

我想在将其投入生产之前测试性能。如果每次读取都调用checkCancelled代理不符合要求,那么每10或100次读取就可以执行此操作。

答案 1 :(得分:0)

如果您的序列化程序不支持取消,您可以执行以下操作:

  • 支持取消上层提取数据

E.g。对于WebClient,我会利用WebClient.CancelAsync等等......