加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – JsonConvert.DeserializeObject和ThreadAbortedException

发布时间:2020-12-15 22:46:28 所属栏目:百科 来源:网络整理
导读:在Xamarin项目中,我有以下代码的PCL库. 我们定义ConcurrentQueue SyncRequest.对于初始化对象初始化,已附加了使用者任务: _syncConsumer = new Task( ProcessSyncQueue,_syncConsumerCancellationTokenSource.Token);_syncConsumer.Start(); ProcessSyncQue
在Xamarin项目中,我有以下代码的PCL库.

我们定义ConcurrentQueue< SyncRequest>.对于初始化对象初始化,已附加了使用者任务:

_syncConsumer = new Task(
                ProcessSyncQueue,_syncConsumerCancellationTokenSource.Token);
_syncConsumer.Start();

ProcessSyncQueue方法扫描同步队列并调用GetSyncableEntity方法:

private async void ProcessSyncQueue()
{
    while (true)
    {
         SyncRequest syncRequest;
         if (_syncQueue.TryDequeue(out syncRequest))
         {
             var syncableEntity = GetSyncableEntity(syncRequest);
         }
    }
}

GetSyncableEntity依次执行Json反序列化:

private T GetSyncableEntity(SyncRequest syncRequest)
{
    T syncableEntity = default(T);

    try
    {
       syncableEntity = JsonConvert.DeserializeObject<T>(syncRequest.SynchronizationContent);
    }
    catch (Exception e)
    {

    }

    return syncableEntity;
 }

在这一步中,我们收到ThreadAbortedException,其中包含’Thread was aborted’消息.
堆栈跟踪:

at Newtonsoft.Json.JsonTextReader.FinishReadStringIntoBuffer(Int32 charPos,Int32 initialPosition,Int32 lastWritePosition)
   at Newtonsoft.Json.JsonTextReader.ReadStringIntoBuffer(Char quote)
   at Newtonsoft.Json.JsonTextReader.ParseProperty()
   at Newtonsoft.Json.JsonTextReader.ParSEObject()
   at Newtonsoft.Json.JsonTextReader.Read()
   at Newtonsoft.Json.JsonReader.ReadAndAssert()
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader,Type objectType,JsonContract contract,JsonProperty member,JsonContainerContract containerContract,JsonProperty containerMember,Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader,Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader,Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader,Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value,Type type,JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value,JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value)

任何人都可以帮助我们了解发生了什么以及如何反序列化?

更新:
我发布了更多代码,因为评论者建议我删除CancellationTokenSource,使用Task.Run来初始化消费者并等待它.
并创建了一些这样的测试实现:

protected void RequestSynchronizationFor(
        string synchronizationKey,T entity)
    {
        if (!_isInitialized)
        {
            InitializeSyncRequestsQueue();
        }

        _syncQueue.Enqueue(GetSyncRequest(synchronizationKey,entity));
    }

所以我们请求实体同步调用RequestSynchronizationFor方法.如果是冷运行,我们从db调用InitializeSyncRequestsQueue并等待Task.Run使用者线程初始化队列.

private async void InitializeSyncRequestsQueue()
    {
        var syncRequests = GetSyncedRequests();

        foreach (var syncRequest in syncRequests)
        {
            _syncQueue.Enqueue(syncRequest);
        }

        await Task.Run(ProcessSyncQueue);
    }

像以前一样的消费者任务做同样的事情:

private async Task ProcessSyncQueue()
    {
        while (true)
        {
            SyncRequest syncRequest;
            if (_syncQueue.TryDequeue(out syncRequest))
            {
                var syncableEntity = GetSyncableEntity(syncRequest);
            }
        }
    }

仍然有同样的例外.不确定它是否合理,但我正在运行单元测试中的代码.有什么建议?

UPDATE2:

在我做了更改后,我在第一个’UPDATE’中发布了,调用堆栈也发生了一些变化:

at Newtonsoft.Json.JsonSerializer.get_MetadataPropertyHandling()
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader,JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value)

更新3:
我在假服务中提取所有代码并且在尝试反序列化时仍然具有相同的异常:

public class JsonDeserializeService<T>
{
    private readonly bool _isInitialized;

    private readonly ConcurrentQueue<SyncRequest> _syncQueue;

    public JsonDeserializeService()
    {
        _isInitialized = false;
        _syncQueue = new ConcurrentQueue<SyncRequest>();
    }

    public void RequestSynchronizationFor(
        string synchronizationKey,entity));
    }

    private async void InitializeSyncRequestsQueue()
    {
        var syncRequests = Enumerable.Empty<SyncRequest>();

        foreach (var syncRequest in syncRequests)
        {
            _syncQueue.Enqueue(syncRequest);
        }

        await Task.Run(ProcessSyncQueue);
    }

    private async Task ProcessSyncQueue()
    {
        while (true)
        {
            SyncRequest syncRequest;
            if (_syncQueue.TryDequeue(out syncRequest))
            {
                var syncableEntity = GetSyncableEntity(syncRequest);
            }
        }
    }

    private T GetSyncableEntity(SyncRequest syncRequest)
    {
        T syncableEntity = default(T);

        try
        {
            syncableEntity = JsonConvert.DeserializeObject<T>(syncRequest.SynchronizationContent);
        }
        catch (Exception e)
        {
        }

        return syncableEntity;
    }

    private SyncRequest GetSyncRequest(string synchronizationKey,T entity)
    {
        return new SyncRequest()
        {
            SynchronizationContent = JsonConvert.SerializeObject(entity),SynchronizationDelayUntil = DateTime.Now
        };
    }
}

从单元测试触发:

public void Syncable_Service_Should_Not_Generate_Exception()
    {
        var syncService = new JsonDeserializeService<FakeSyncableEntity>();
        syncService.RequestSynchronizationFor("syncKey",new FakeSyncableEntity() { Content = "Content" });
    }

解决方法

这种行为的原因很简单.
您的测试比异步任务更早结束.当测试结束时,它会为子线程引发ThreadAbortException.

您需要调用task.Wait()以使主线程等待任务完成.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读