Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use Async/Await with dbContext? If so, when should I use ConfigureAwait(false)?

Say I have the following snippet:

using (var db = new dbContext()){
     var user = db.Users.Find(3);
     user.Name = "newName";
     var viewModel = GetViewModelAndDoStuffToUser(user);
     db.SaveChanges();
     return viewmodel;
}

Now I'm trying to improve the performance of this snippet at scale by leveraging async/await, but I've read that dbContext is not "thread safe". So I'm a bit confused about:

  1. Whether or not I can use async/await with calls relating to dbContext
  2. Whether or not I should use .ConfigureAwait(false) when I do. I've read that this tells us not to re-enter the ".NET Context" which is needed by MVC and WebApi controllers - but this is the service layer of an application serving those controllers. I've also read that using this will prevent deadlocks.
  3. Whether or not - in more complicated scenarios - I can parallelize calls using the same instance of dbContext by using Task.WhenAll()

Would the following snippet be a scalable, thread-safe step in the right direction?

using (var db = new dbContext()){
     var user = await db.Users.FindAsync(3).ConfigureAwait(false);
     user.Name = "newName";
     var viewModel = await GetViewModelAndDoStuffToUserAsync(user).ConfigureAwait(false);
     await db.SaveChangesAsync().ConfigureAwait(false);
     return viewmodel;
}
like image 814
SB2055 Avatar asked Oct 23 '16 00:10

SB2055


People also ask

When should I use ConfigureAwait?

A situation to use ConfigureAwait(true) is when performing await in a lock, or using any other context/thread specific resources. This requires a synchronization context, which you will have to create, unless you are using Windows Forms or WPF, which automatically create a UI synchronization context.

When should I use the task ConfigureAwait Boolean method?

When an asynchronous method awaits a Task directly, continuation usually occurs in the same thread that created the task, depending on the async context. This behavior can be costly in terms of performance and can result in a deadlock on the UI thread. To avoid these problems, call Task. ConfigureAwait(false) .

What is ConfigureAwait () used for?

ConfigureAwait(continueOnCapturedContext: false) is used to avoid forcing the callback to be invoked on the original context or scheduler. This has a few benefits: Improving performance.


1 Answers

Short answer is "Yes", "Yes", and "Yes".

Long answer is that although db context is not thread-safe, async/await constructs are not passing db context to other threads anyway, so you are safe here.

As far as the call to ConfigureAwait(false) goes, you should do it everywhere except UI code. Since database code is rarely placed in UI layer (it is never placed in UI level in high-quality production code) you should use ConfigureAwait(false) in every asynchronous call that you make on backend.

Finally, if you make multiple tasks with calls to async methods of db context, you create co-routines. They parallelize work outside your system (e.g. make concurrent DB calls), but on your end they are not running concurrently. This keeps your db context safe, because any changes to it are applied sequentially.

like image 70
Sergey Kalinichenko Avatar answered Nov 11 '22 10:11

Sergey Kalinichenko