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; }
}