What is the best practice in EF Core for using parallel async calls with an Injected DbContext?

Using any context.XyzAsync() method is only useful if you either await the called method or return control to a calling thread that’s doesn’t have context in its scope.

A DbContext instance isn’t thread-safe: you should never ever use it in parallel threads. Which means, just for sure, never use it in multiple threads anyway, even if they don’t run parallel. Don’t try to work around it.

If for some reason you want to run parallel database operations (and think you can avoid deadlocks, concurrency conflicts etc.), make sure each one has its own DbContext instance. Note however, that parallelization is mainly useful for CPU-bound processes, not IO-bound processes like database interaction. Maybe you can benefit from parallel independent read operations but I would certainly never execute parallel write processes. Apart from deadlocks etc. it also makes it much harder to run all operations in one transaction.

In ASP.Net core you’d generally use the context-per-request pattern (ServiceLifetime.Scoped, see here), but even that can’t keep you from transferring the context to multiple threads. In the end it’s only the programmer who can prevent that.

If you’re worried about the performance costs of creating new contexts all the time: don’t be. Creating a context is a light-weight operation, because the underlying model (store model, conceptual model + mappings between them) is created once and then stored in the application domain. Also, a new context doesn’t create a physical connection to the database. All ASP.Net database operations run through the connection pool that manages a pool of physical connections.

If all this implies that you have to reconfigure your DI to align with best practices, so be it. If your current setup passes contexts to multiple threads there has been a poor design decision in the past. Resist the temptation to postpone inevitable refactoring by work-arounds. The only work-around is to de-parallelize your code, so in the end it may even be slower than if you redesign your DI and code to adhere to context per thread.

Leave a Comment