I wonder in which situations I will run into problems when using
ConfigureAwait(false)
in my (Xamarin) MVVM approach. This is mainly because I do not fully understand the synchronization context a view and a viewmodel and its properties and the underlaying model have to each other...
1 What about observable collections?
// VM
public ObservableCollection<SomeThing> SomeThings { get; set; }
// ...
public Task InitWorkload()
{
SomeThings = await DbService.GetSomeThings(); // <-- Should need synchronization context, doesn't it?
}
// Service
public Task<SomeThings> GetSomeThings()
{
result = await CallToDb.ConfigureAwait(false); // <-- This is UI agnostic and shouldn't care about context or does it?
return result;
}
2 What about Navigation (in this case with the help of FreshMvvm)?
private async Task CloseWindow()
{
await CoreMethods.PopPageModel(); // <-- Should need synchronization context, doesn't it?
}
To answer the title question, "When is the Usage of
ConfigureAwait(false)
in ViewModels problematic?" is "Never." Its use in a view model is irrelevant. What matters is what thread you want to run on after the async method is called, whether or not you are in a view model is irrelevant. The only time that usingConfigureAwait(false)
may be problematic is if you want to return to the thread that was running before the async method was called.And for reference, docs on the SynchronizationContext class.
Maybe explaining what
ConfigureAwait(false)
does is the best approach to answer this. When one calls an async method like so:The code
var y = x
will run on the same thread that the work was being done on before the async method was called, i.e the Synchronization context prior to the async method call, however if you use ConfigureAwait(false), e.g.:then the code
var y = x
will run on the same thread that theSomeMethodAsync
method was running on when it returned. (PresumablySomeMethodAsync
usesTask.Run
orThread.StartNew
which are the main ways of launching a new thread...await
does not start a new thread, it is only syntactic sugar to allow your async code to be more readable so that the code following the async method call does not have to be an a delegate method or lambda, but can be in-line just like synchronous code.)So what you need depends on what might need to be updated. Any UI updates need to run on the Main or UI thread. You can always marshal code to the Main or UI thread with
Device.BeginInvokeOnMainThread(Action)
.Generally, when you are in a, let's say, button click handler event, the event handler method starts running on the UI thread. If you need to call one async method and then update some UI, then do not use
ConfigureAwait(false)
so that after the async method you return to the Main/UI thread and you can update your UI. If you do not need to update any UI, then feel free to callConfigureAwait(false)
so that you do not unnecessarily return to the UI thread when there is no need to be running on that thread.In some cases if you are calling multiple async methods from one method that starts on the UI thread, you might want to use
ConfigureAwait(false)
such that you are not going back and forth to the UI thread from background threads multiple times, which cause performance issues, but rather all of the Non-UI work is done on a background thread, and then you just manually marshal back to the UI thread when and if needed.As for an
ObservableCollection
, it does not have thread affinity, i.e. when an object can only be updated or modified on the same thread that it was created on, but it is also not thread safe, so your best plan is to only access or change the ObservableCollection on the same thread that it was created on, most likely he Main/UI thread.