c# - JsonConvert.DeserializeObject 和 ThreadAbortedException

标签 c# json xamarin json.net task

在 Xamarin 项目中,我有包含以下代码的 PCL 库。

我们定义一个 ConcurrentQueue<SyncRequest> .消费者在对象初始化时为此 Task已附上:

_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带有“线程被中止”的消息。 堆栈跟踪:

   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, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, 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初始化消费者和await它。 并创建了一些这样的测试实现:

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

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

所以我们请求实体同步调用RequestSynchronizationFor方法。如果是冷运行,我们从数据库调用 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);
            }
        }
    }

仍然有同样的异常。不确定它是否明智,但我正在运行单元测试中的代码。有什么建议吗?

更新 2:

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

   at Newtonsoft.Json.JsonSerializer.get_MetadataPropertyHandling()
   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, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, 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)

更新 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,
        T entity)
    {
        if (!_isInitialized)
        {
            InitializeSyncRequestsQueue();
        }

        _syncQueue.Enqueue(GetSyncRequest(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()让主线程等待任务完成。

关于c# - JsonConvert.DeserializeObject 和 ThreadAbortedException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45573183/

相关文章:

c# - 您将 dpiAware 代码放在 clickonce list 中的什么位置?

c# - Directory.EnumerateFiles 是否锁定了它试图复制的文件?

c# - 正则表达式删除两个字符串之间的连字符

java - 为什么会出现 "No com.badlogic.gdx.scenes.scene2d.ui.ScrollPane$ScrollPaneStyle registered with name: default"错误以及如何解决?

java - 映射字符串数组列表获取键和值

c# - 在 ConfigureServices() 中添加 AddMvc() 服务两次是 Asp.Net Core 中的一个好习惯吗?

c# - Xamarin.Forms 绑定(bind)不起作用

c# - 如何在 Xamarin 上启动项目?

android - Xamarin:当应用程序未运行时 BroadcastReceiver 未收到

c# - GUI GroupPanel 鼠标事件