Using ConfigureAwait in nested async methods

Viewed 571

I'm developing Blazor Server web application, and I'm torn on using .ConfigureAwait(false). I know that I shouldn't use it in component code, but I'm not sure about nested code. For example: I'm calling async method to update data on page on button click. This method itself also calls async method to make request to the API. Question is - should this nested method (API request) be called with ConfigureAwait(false) or not?

Edit: Adding Code to demonstrate more clearly:

This method is called from button OnClick

protected async Task GridRefresh()
{
    Models = null;
    _errorMessage = null;
    try
    {
        Models = await _dataService.GetDataAsync(Active);
    }
    catch (Exception ex)
    {
        _errorMessage = ex.Message.Split("Message:").Last();
    }
}

This method is located in DataService class that I add to my component using Dependency Injection

public async Task<IEnumerable<ItemViewModel>> GetDataAsync(int id)
{
    var container = await ApiWrapper.getByIDAsync(id);
    if(container == null)
        throw new Exception($"Container with code {id} not found!");

    return container.Items;
}

Question is: should I use ConfigureAwait in GetDataAsync method?

var container = await ApiWrapper.getByIDAsync(id).ConfigureAwait(false);
3 Answers

You should do the same thing you'd do in desktop applications.

  • To update the UI, you must to be on its synchronization context, so you should not use ConfigureAwait(false) when updating the UI.
  • In non-UI code there's no need to get back to the UI context, so you should probably use ConfigureAwait(false) and let the top-level code decide whether it needs to get back to the UI context. This way you avoid possible deadlocks if the UI thread/context is busy.
  • In library code you should use ConfigureAwait(false) to avoid forcing a context switch and possibly a deadlock

In small, clean components (the kind of components you should be building anyway) there shouldn't be such a big problem if you omit ConfigureAwait(false).

In library code, omitting ConfigureAwait(false) can easily lead to deadlocks, especially during debugging. In fact, I wonder if the deadlocks experienced by some popular local storage package is caused by some missed ConfigureAwait calls

The same rules apply to any UI framework.

ConfigureAwait(false), affords a very small efficiency. However, you would generally keep it out of top level UI code.

To answer the question directly:

This method is located in DataService class that I add to my component using Dependency Injection. should I use ConfigureAwait in GetDataAsync method?

In this scenario, it's fine.

The long story

Synchronization context

Blazor uses a synchronization context (SynchronizationContext) to enforce a single logical thread of execution. A component's lifecycle methods and any event callbacks that are raised by Blazor are executed on the synchronization context.

Blazor Server's synchronization context attempts to emulate a single-threaded environment so that it closely matches the WebAssembly model in the browser, which is single threaded. At any given point in time, work is performed on exactly one thread, giving the impression of a single logical thread. No two operations execute concurrently.

In short, it runs on a single UI thread and with its own synchronization context, so don't call ConfigureAwait(false) in top level code, just use the same logic as you do on any other UI framework that has as synchronization context for a message pump or dispatcher.

Which seems to be backed up by SteveSandersonMS in this github question Blazor Question: ConfigureAwait(false) in Server-Side Blazor?

Yes, Blazor Server is a UI framework which requires your code to run on its sync context. Therefore do not use ConfigureAwait(false) within your Blazor component code.

and also from mkArtakMSFT in this github question Guidance on using ConfigureAwait(...) in async life-cycle methods in Razor component

Our guidance is to simply not use ConfigureAwait in Blazor.

...

Just for UI related scenarios. For non-UI impacting scenarios (query a data store or a service) ConfigureAwait(false) is useful.

Let's review the GetDataAsync method:

public async Task<IEnumerable<ItemViewModel>> GetDataAsync(int id)
{
    var container = await ApiWrapper.getByIDAsync(id);
    if(container == null)
        throw new Exception($"Container with code {id} not found!");

    return container.Items;
}

After the awaiting of the getByIDAsync, two lines of code will be executed:

if(container == null)
    throw new Exception($"Container with code {id} not found!");

return container.Items;

Currently these two lines will be executed on the Blazor's synchronization context. Is it required? It depends on the code running in the accessor of the Items property of the container object. Is there any code that interacts with any UI component? If yes, or if you are not sure, then you shouldn't add ConfigureAwait(false) in the awaiting of the getByIDAsync. If no (which is the most probable), then using ConfigureAwait(false) will have no negative repercussions. The positive aspects of adding the ConfigureAwait(false) is that will allow the caller to block on async code without deadlocking your application:

Models = _dataService.GetDataAsync(Active).Result; // Bad practice

Adding the ConfigureAwait(false) will also make your code slightly more efficient. And by slightly I mean practically negligible. So don't base your decision on this, but on what the code does, and on how it is intended to be used.

Related