Should I use ConfigureAwait(false) in places like Repository?

3.6k Views Asked by At

Just read this article about ConfigureAwait and it made me think on an issue I haven't been able to come to peace with for some time now.

Consider the code below. Each dependency uses await to make the call asynchronous. My concern is that each time we exit an await it goes back to the UI thread and I don't want that until I'm actually at the top level where the UI needs to be updated in order to reduce thread context switching. That made me think that ConfigureAwait(false) should be used in layers below the UI to avoid unnecessary Post's (SynchronizationContext) to the UI thread.

What do you think? Is this necessary or am I way off? Or will the runtime actually take care of this for me?

Without ConfigureAwait(false):

public class ViewModel
{
    private readonly Service service;
    private readonly ICommand updateCommand;
    
    public ViewModel(Service service)
    {
        this.service = service;
        updateCommand = new RelayCommand(UpdateUser);
    }

    private async void UpdateUser()
    {
        Cursor.ShowWait();
        await service.UpdateUser(SelectedUser);
        Cursor.ShowDefault();
    }
}

public class Service
{
    private readonly Repository repository;
    
    public Service(Repository repository)
    {
        this.repository = repository;
    }
    
    public async Task UpdateUser(Model.User user)
    {
        var domainUser = Convert(user);
        await repository.UpdateUser(domainUser);
    }
}

public class Repository
{
    private readonly MyDbContext context;
    
    public Repository(MyDbContext context)
    {
        this.context = context;
    }
    
    public async Task UpdateUser(User user)
    {
        context.Users.Update(user);
        await context.SaveChangesAsync();
    }
}

public class MyDbContext : DbContext
{
    public DbSet<User> Users { get; set; }
}   

With ConfigureAwait(false)

public class ViewModel
{
    private readonly Service service;
    private readonly ICommand updateCommand;
    
    public ViewModel(Service service)
    {
        this.service = service;
        updateCommand = new RelayCommand(UpdateUser);
    }

    private async void UpdateUser()
    {
        Cursor.ShowWait();
        await service.UpdateUser(SelectedUser);
        Cursor.ShowDefault();
    }
}

public class Service
{
    private readonly Repository repository;
    
    public Service(Repository repository)
    {
        this.repository = repository;
    }
    
    public async Task UpdateUser(Model.User user)
    {
        var domainUser = Convert(user);
        await repository.UpdateUser(domainUser).ConfigureAwait(false);
    }
}

public class Repository
{
    private readonly MyDbContext context;
    
    public Repository(MyDbContext context)
    {
        this.context = context;
    }
    
    public async Task UpdateUser(User user)
    {
        context.Users.Update(user);
        await context.SaveChangesAsync().ConfigureAwait(false);
    }
}

public class MyDbContext : DbContext
{
    public DbSet<User> Users { get; set; }
}
2

There are 2 best solutions below

2
On BEST ANSWER

You should always use configureAwait in libraries, even if the code (in my opinion) is much worse than without.

Check microsoft best practices here

By using ConfigureAwait, you enable a small amount of parallelism: Some asynchronous code can run in parallel with the GUI thread instead of constantly badgering it with bits of work to do.

Aside from performance, ConfigureAwait has another important aspect: It can avoid deadlocks.

Be careful of when you can't use it:

You should not use ConfigureAwait when you have code after the await in the method that needs the context. For GUI apps, this includes any code that manipulates GUI elements, writes data-bound properties or depends on a GUI-specific type such as Dispatcher/CoreDispatcher.

For ASP.NET apps, this includes any code that uses HttpContext.Current or builds an ASP.NET response

In repositories, it's almost always the case that you can use it as you don't need to resume into the same Synchronization context.

0
On

The answer by Athanasios is good. But I thought I'd add to those points.

Libraries

It is recommended in libraries because, if a consumer of your library decides to synchronously wait on your asynchronous method, it can cause a deadlock.

An exception to this is if you are providing synchronous methods and asynchronous methods (i.e. DoSomething() and DoSomethingAsync()), then you don't need to worry about that. If the consumer of your library needs to use your code synchronously, they can use the synchronous method. And if they wait synchronously on your asynchronous method, then, well, that's their own problem.

Parallelism

The best advice I can give about ConfigureAwait(false) is don't sprinkle it everywhere blindly. First because of possibly losing context when you don't expect to, but second is the implicit parallelism. The whole benefit of async and await is being able to run asynchronous code in the same manner as you would synchronous code. And, largely, asynchronous != parallel. But if you use ConfigureAwait(false), your code after the await could run in parallel when you don't expect it to, and your code may not be thread safe.

Stephen Cleary discusses this in his article about ASP.NET Core SynchronizationContext (see the "Beware Implicit Parallelism" heading). ASP.NET Core has no synchronization context so ConfigureAwait(false) has no effect there, but it applies to any app that does normally have a context when using ConfigureAwait(false) too. He gives example code there where non-thread safe code can end up running in parallel.

Conclusion

Don't use it unless you have a conscious reason to.