Ho un'app WinForms e ho del codice che deve essere eseguito sul thread dell'interfaccia utente. Tuttavia, il codice dopo lo await
viene eseguito su un thread diverso.attende senza ConfigureAwait (false) continua su un thread diverso
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());
}
Ho anche provato ad aggiungere in modo esplicito ConfigureAwait(true)
, ma non fa differenza. La mia comprensione è stata che se ometto lo ConfigureAwait(false)
, la continuazione dovrebbe essere eseguita sul thread originale. È sbagliato in alcune situazioni?
Ho anche notato che se aggiungo un controllo alla raccolta prima dell'attesa, la continuazione viene eseguita magicamente sul thread corretto.
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());
}
La mia domanda è:
- Perché succede questo?
- Come convinco la continuazione per l'esecuzione sul thread dell'interfaccia utente (idealmente senza fare il mio hack di aggiungere un controllo e rimuoverlo)?
Per riferimento, ecco le parti importanti di DoSomethingAsync
. Invia una richiesta HTTP usando 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.
}
Perché pensi che funzioni su un thread diverso? Dove viene eseguito questo codice? gestore di eventi? – i3arnon
So che viene eseguito su un thread diverso perché il codice dopo l'attesa genera un'eccezione: "Operazione cross-thread non valida: controllo 'mainContainer' a cui si accede da un thread diverso dal thread su cui è stato creato". –
Sì, il codice viene eseguito in un gestore eventi. Aggiornerò la mia domanda –