反序列化JSON

时间:2015-10-13 02:16:48

标签: c# multithreading json.net async-await httpclient

所以我为我的客户制作了一个请求包装器,一切正常。但突然(我不知道为什么)JsonConvert.DeserializeObject<T>(c)抛出经典异常

  

调用线程无法访问此对象,因为另一个线程拥有它

嗯,我没有看到任何其他线程,但这个。所有这些都是局部变量,根据Newtonsoft https://github.com/JamesNK/Newtonsoft.Json/issues/469

  

每次反序列化对象时都会创建一个新的JsonSerializerInternalReader

你有任何线索,这个例外正在讨论的另一个线程在哪里?

    public static Task<Response<T>> _reqWrapper<T>(Func<Task<HttpResponseMessage>> request) 
        where T : class
    {
        return Task.Run(async () =>
        {
            var response = new Response<T>();

            var hrm = await request().ConfigureAwait(false);                              
            var c = await hrm.Content.ReadAsStringAsync().ConfigureAwait(false);
            response.Content = JsonConvert.DeserializeObject<T>(c);

            return response;
        });

在没有运气的情况下试过这个。

response.Content = await Task.Run(() => JsonConvert.DeserializeObject<T>(c));

更新

为了确保那条线是我做的那个:

T t = null;
try
{
    t = JsonConvert.DeserializeObject<T>(c);
}
catch { }
response.Content = t

一切都运转良好。有线索吗?

更新2

堆栈跟踪

我在这里看到的是序列化程序正在尝试访问主窗口。我不得不说这是在ShowDialog()窗口内发生的,所以我猜主窗口不可用。但我不确定我是否正确或如何解决这个问题。

  System.Windows.Threading.Dispatcher.VerifyAccess()上的

     在System.Windows.Application.get_MainWindow()      在C:中的ControliWindows.Globals.Controli.get_Window():      在C:中的ControliWindows.Globals.Framework.Modalizer.SaveableModel1..ctor()中...      在C:中的ControliWindows.Views.Modals.AccountMm..ctor():      在CreateControliWindows.Views.Modals.AccountMm()      at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader,JsonObjectContract objectContract,JsonProperty containerMember,JsonProperty containerProperty,String id,Boolean&amp; createdFromNonDefaultCreator)      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)      在Newtonsoft.Json.JsonSerializer.Deserialize(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)      在ControliWindows.Globals.Connection。&lt;&gt; c__DisplayClass39_0`1。&lt;&lt; _reqWrapper&gt; b__0&gt; d.MoveNext()在C:...

3 个答案:

答案 0 :(得分:2)

  

在System.Windows.Threading.Dispatcher.VerifyAccess()处于System.Windows.Application.get_MainWindow()的ControliWindows.Globals.Controli.get_Window()位于C:...中的ControliWindows.Globals.Framework.Modalizer。 C中的SaveableModel1..ctor():...在C:...中的ControliWindows.Views.Modals.AccountMm..ctor()

这是你问题的根源。以下是正在发生的一系列事件:

  • 您的TControliWindows.Views.Modals.AccountMmDeserializeObject必须新建一个
  • AccountMm的构造函数正在创建ControliWindows.Globals.Framework.Modalizer.SaveableModel1
  • SaveableModel1的构造函数正在读取属性ControliWindows.Globals.Controli.Window
  • Controli.Window中正在阅读属性System.Windows.Application.Window
  • Application.Window只能从UI线程读取,整个事件链发生在Threadpool线程上并导致异常。

最简单的解决方案是ControliWindows.Globals.Controli.Window检测它是否不在UI线程上,如果它没有调用UI来获取Application.Window的值。

public static class Controli
{
    public Window Window
    {
        get
        {
            var application = Application.Current;
            if(application == null)
                return null;
            try
            {
                return application.MainWindow;
            }
            catch(InvalidOperationException)
            {
                return application.Dispatcher.Invoke(() => application.MainWindow);
            }
        }
    }
}

答案 1 :(得分:0)

通过使用ConfigureAwait(false),您明确告诉等待在执行等待之后不要尝试在同一线程上恢复执行代码。

来自the documentation

  

continueOnCapturedContext

     

类型:System.Boolean

     

true 尝试将继续编组回到捕获的原始上下文;否则, false

请尝试使用ConfigureAwait(true)

答案 2 :(得分:0)

在另一个线程中发生了消毒。它打开自己的线程