I have a WinForms app, and I have some code that needs to run on the UI thread. However, the code after the await
runs on a different thread.
protected override async void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
// This runs on the UI thread.
mainContainer.Controls.Clear();
var result = await DoSomethingAsync();
// This also needs to run on the UI thread, but it does not.
// Instead it throws an exception:
// "Cross-thread operation not valid: Control 'mainContainer' accessed from a thread other than the thread it was created on"
mainContainer.Controls.Add(new Control());
}
I also tried explicitly adding ConfigureAwait(true)
, but it makes no difference. My understanding was that if I omit ConfigureAwait(false)
, then the continuation should run on the original thread. Is this incorrect in some situations?
I've also noticed that if I add a control to the collection before the await, then the continuation magically runs on the correct thread.
protected override async void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
// This runs on the UI thread.
mainContainer.Controls.Add(new Control());
mainContainer.Controls.Clear();
var result = await DoSomethingAsync();
// This also runs on the UI thread now. Why?
mainContainer.Controls.Add(new Control());
}
My question is:
- Why is this happening?
- How do I convince the continuation to run on the UI thread (ideally without doing my hack of adding a control and removing it)?
For reference, here are the important parts of DoSomethingAsync
. It submits an HTTP request using RestSharp.
protected async Task DoSomethingAsync()
{
IRestRequest request = CreateRestRequest();
// Here I await the response from RestSharp.
// Client is an IRestClient instance.
// I have tried removing the ConfigureAwait(false) part, but it makes no difference.
var response = await Client.ExecuteTaskAsync(request).ConfigureAwait(false);
if (response.ResponseStatus == ResponseStatus.Error)
throw new Exception(response.ErrorMessage ?? "The request did not complete successfully.");
if (response.StatusCode >= HttpStatusCode.BadRequest)
throw new Exception("Server responded with an error: " + response.StatusCode);
// I also do some processing of the response here; omitted for brevity.
// There are no more awaits.
}