Call from Invalid Thread possibly related to Avalonia
Getting a "Call from Invalid Thread" exception when running this chunk of code from an Avalonia context.
(excecption happens at
var tcpClient = await this.listener.AcceptTcpClientAsync(internalToken);
).
Doesn't happen when called from a CLI context.3 Replies
Okay wrapping my event callback in a
Dispatcher
fixed it. Hmm...in general with Avalonia and similar UI frameworks (such as WPF), you aren't allowed to touch the UI thread in any way from any other thread
without first marshalling it back to that thread via a specific API -- which in avalonia's case is the Dispatcher, as you found
i don't know where in your callstack here you're touching the UI thread's stuff, so I might be wrong. but it's the first explanation that comes to my mind
this is something to keep in mind whenever you use Task.Run etc. in a UI project
Couple of things:
Concerning your use of
Task.Run
:
Queues the specified work to run on the thread pool and returns a Task object that represents that work. A cancellation token allows the work to be cancelled if it has not yet started.Your
internalToken
will only be checked before the passed delegate starts execution.
Also, if you were to move
out of the Task.Run
, you could call .ConfigureAwait(continueOnCapturedContext: true)
on the tasks returned by AcceptTcpClientAsync(internalToken)
and HandleClientAsync(tcpClient, internalToken)
. This causes execution to continue on the ui thread after asynchronously returning from either operation.
All of this of course only makes sense if StartAsync
is being called from the UI-thread in the first place.
As @Becquerel (ping on reply please) points out, you may only perform certain actions on the UI-thread, and Dispatcher
marshals the passed action to the UI-thread. The reason you are not on the UI-thread at await this.listener.AcceptTcpClientAsync(internalToken)
is because Task.Run
schedules the delegate passed on the thread pool.