when I perform an async call on HttpClient from the (Winforms) UI thread my UI gets blocked. its best noticed when moving the window around.
If I wrap the call in Task.Run the app runs smooth.
var items = await HttpClient.GetStuffAsync();
vs
var items = await task.Run((() => HttpClient.GetStuffAsync());
my expectaion is that the async methods dont block the current thread.
Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.
You aren't using ConfigureAwait(false) prior to waiting the task from HttpClient.GetStuffAsync() and because it's winforms there will be a synchronisation context active so the task scheduler will attempt to push completions back to the main thread. Try with the configuration and see if it helps.
because it's winforms there will be a synchronisation context
In combination with ConfigureAwait(false) it can give you a System.InvalidOperationException, if in the continuation you'll access controls (UI thread).
the async methods dont block the current thread.
I didn't investigate the problem, but it seems as the async request doesn't block the UI-thread, but the continuation / the processing of the results (e.g. a huge string).
Try to just use the status-code from the response and not the actual content, then it runs smooth in my demo.
With a huge content from the response it's smooth while the fetch happens, then it starts to block the UI-thread.
In combination with ConfigureAwait(false) it can give you a System.InvalidOperationException, if in the continuation you'll access controls (UI thread).
Yes, that is expected. You should follow the normal winforms rules around checking for and marshalling back to the UI thread. If you want long running work not to block the UI thread then it needs to happen on a separate thread and if you use a separate thread you have to be careful to push updates back onto the UI thread.
You aren't using ConfigureAwait(false) prior to waiting the task from HttpClient.GetStuffAsync()
I have a workaround that unblocks the UI.
my issue is why do I need workarounds?
why doesnt the http client send my request in an async fashion and unblock the UI thread?
because that is what having an async get method implies for me!
want long running work not to block the UI thread then it needs to happen on a separate thread
what is the longrunning work that is happening in the ui thread? im using an async method!
why doesnt the http client send my request in an async fashion and unblock the UI thread?
because that is what having an async get method implies for me!
It does, the waiting is done on another thread but any subsequent code will come back to the main thread.
Unless you can demonstrate that the async wait itself (not following work) blocks the UI thread then this is working as expected to me.
I think you need to do some reading into how async works and change your expectations from magical thinking to reality based.
Unless you can demonstrate that the async wait itself (not following work) blocks the UI thread then this is working as expected to me.
It wouldn't be the first time. I think in early versions the proxy was resolved synchronously before the actual asynchronous call.
@JanEggers To stop any controversy, could you try changing your code to:
_ = HttpClient.GetStuffAsync();
and see if the issue persists? Basically removing any work, and just leaving the synchronous part of the HttpClient call.
@kevingosse thx to pointing me in the right direction.
the issue was that the payload deserialization was blocking the ui thread.
with my additional task run the serialization happens in the background and without it in the ui.
that was not obvious to me as the code generated by nswag uses configurawait(false) so i thought deserializations happens in the background.
anyway thx for clarifiing
Most helpful comment
You aren't using
ConfigureAwait(false)prior to waiting the task fromHttpClient.GetStuffAsync()and because it's winforms there will be a synchronisation context active so the task scheduler will attempt to push completions back to the main thread. Try with the configuration and see if it helps.