Reputation: 6720
So I made a request wrapper for my clients, and everything was working fine. But suddenly (I have no clue why) JsonConvert.DeserializeObject<T>(c)
throws the classic exception
The calling thread cannot access this object because a different thread owns it
Well I don't see any other thread but this one. All of them are local variables and according to Newtonsoft https://github.com/JamesNK/Newtonsoft.Json/issues/469
A new JsonSerializerInternalReader is created each time you deserialize an object
Do you have any clue where is the another thread this exception is talking about?
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;
});
Already tried this without luck.
response.Content = await Task.Run(() => JsonConvert.DeserializeObject<T>(c));
Update
To be sure that that line is the one throwing I made this:
T t = null;
try
{
t = JsonConvert.DeserializeObject<T>(c);
}
catch { }
response.Content = t
And everything is running fine. Any clues?
Update 2
Stack trace
What I see here is that the serializer is trying to access the main window. I have to say that this is happening inside a ShowDialog()
window, so I guess the main window is not available. But I'm not sure if I am correct or how to fix this.
at System.Windows.Threading.Dispatcher.VerifyAccess() at System.Windows.Application.get_MainWindow() at ControliWindows.Globals.Controli.get_Window() in C:... at ControliWindows.Globals.Framework.Modalizer.SaveableModel1..ctor() in C:... at ControliWindows.Views.Modals.AccountMm..ctor() in C:... at CreateControliWindows.Views.Modals.AccountMm() at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, String id, Boolean& 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) at 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) at ControliWindows.Globals.Connection.<>c__DisplayClass39_0`1.<<_reqWrapper>b__0>d.MoveNext() in C:...
Upvotes: 2
Views: 2375
Reputation: 127593
at System.Windows.Threading.Dispatcher.VerifyAccess() at System.Windows.Application.get_MainWindow() at ControliWindows.Globals.Controli.get_Window() in C:... at ControliWindows.Globals.Framework.Modalizer.SaveableModel1..ctor() in C:... at ControliWindows.Views.Modals.AccountMm..ctor() in C:... at
That is the source of your problem. Here is the series of events that is happening:
T
is a ControliWindows.Views.Modals.AccountMm
and DeserializeObject
must make a new one of themAccountMm
's constructor it is creating a ControliWindows.Globals.Framework.Modalizer.SaveableModel1
SaveableModel1
's constructor it is reading the property ControliWindows.Globals.Controli.Window
Controli.Window
it is reading the property System.Windows.Application.Window
Application.Window
can only be read from the UI thread, this whole chain of events happens on a Threadpool thread and causes your exception.The easiest solution is have ControliWindows.Globals.Controli.Window
detect if it is not on the UI thread and if it is not invoke to the UI to get the value of 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);
}
}
}
}
Upvotes: 2
Reputation: 2509
By using ConfigureAwait(false)
you are explicitly telling your await to not try to resume the execution of the code on the same thread after performing your await.
From the documentation:
continueOnCapturedContext
Type: System.Boolean
true to attempt to marshal the continuation back to the original context captured; otherwise, false.
Try using ConfigureAwait(true)
instead.
Upvotes: 0