Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

strict MVVM and Task.ConfigureAwait(false)

I'm rewriting some parts of our MVVM framework to make use of the async/await features, consider the following VM code:

private async Task LoadDossier(int ID)
    {
        //VM INotifyProperty
        Dossiers = new ObservableCollection<Dossier>(await BubManager.GetAllBubDossiersForEmployeeByDossierIdAsync(ID).ConfigureAwait(false));
        //VM INotifyProperty
        SelectedDossier = Dossiers.First(x => x.Id == ID);
        //VM INotifyProperty
        DossierEmployer = await EmployerManager.GetEmployerByIdAsync(SelectedDossier.EmployerId).ConfigureAwait(false);
        //VM INotifyProperty
        DossierEmployee = await EmployeeManager.GetEmployeeByIdAsync(SelectedDossier.EmployeeId).ConfigureAwait(false);
        //All VM INotifyProperties
        if (SelectedDossier != null && DossierEmployer != null)
        {
            RszNr = DossierEmployer.RszNr;
            FundsNr = DossierEmployer.FundsNr;
            RrNr = DossierEmployee.RrNr;
        }
        RefreshGlobalCommanding();
    }

As I'm using strict MVVM there is not a single property here that needs the UI thread, therefore I'm using ConfigureAwait(false) everywhere. I am aware that this is not possible when adding/removing from an ObservableCollection, but this is not the case here.

  • Is this code a good practice?
  • If it is, then why can't you make this the default behavior? Constantly having to type ConfigureAwait(false) doesn't help readability IMO

EDIT

Following the discussion with Stephen I came to the conclusion that It's basically the same thing.

  • If you use ConfigureAwait(false), you are telling WPF that the callback doesn't have to be on the UI thread. When setting an INotifyProperty, WPF makes sure the UI thread gets the notification.
  • If you don't WPF makes sure the callback is on the UI thread and there's no problem at all.

Both cases make WPF do the UI thread marshalling at some point. However, I compared the performance of the two and there is a significant difference. I executed a loop 1000 times where an object gets bound to a view and then is set to null again, here are the results in milliseconds:

One await call with a task delay of 10ms

  • 15623ms with ConfigureAwait(false)
  • 51700ms without

Three await calls with a task delay of 10ms

  • 46917ms with ConfigureAwait(false)
  • 82647ms without

This benchmark is far from perfect, but it seems marshalling back properties to the UI thread is less costly than obliging everything after an await call to run on the same thread. This needs more testing to give a definitive answer for all scenario's however.

I'm just putting this here to document that there are differences between the two. My advice would be to not use ConfigureAwait in this scenario because it raises the chance for exceptions when altering your code, is less readable and colleagues may not understand the point and get a false sense of security by using this.

like image 745
Arne Deruwe Avatar asked Oct 24 '25 09:10

Arne Deruwe


1 Answers

Is this code a good practice?

Personally, I choose to treat all data-bound properties as though they had UI-affinity.

One reason is that different MVVM frameworks have different capabilities in this regard; it's true that WPF will handle this for you (for simple properties), but others will not.

If it is, then why can't you make this the default behavior?

When async was in CTP, there were tons of discussions regarding this default behavior of await. There are pros and cons each way.

like image 80
Stephen Cleary Avatar answered Oct 26 '25 22:10

Stephen Cleary