1

Could you somebody explain to me a strange behavior of async EFCore methods? I have ASP.NET WebApi application using EFCore DB context. When I try execute basically something like that:

await db.AnyAsync(entity.Compare());
await db.AddAsync(entity);
await db.SaveAsync();

I getting exception

A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.

I have some idea where is the problem, but I have to be sure.

Heretic Monkey
  • 10,498
  • 6
  • 45
  • 102
Lukas
  • 11
  • 1
  • 2
    _I have some idea where is the problem_ - so what is the idea? – Fabio Jul 03 '18 at 09:44
  • What is entity.Compare()? – bubi Jul 03 '18 at 10:04
  • bubi: entity.Compare() is Expression tree function for comparison entities, substitute that by somethig like `e => e.Id == entity.Id` if you want – Lukas Jul 03 '18 at 10:46
  • Fabio: My idea is little bit vague, but I think in Web Api is not guaranteed that awaited function will be executed on the same thread as a caller. When the first method was executed, EF Core attach the entity and mark that from wich thread were was been attached. The second method make the same, but from different thread and when I try to save changes, the EFCore evaluate that as multi-threaded operation... – Lukas Jul 03 '18 at 11:16
  • Can you provide some sample app where we can reproduce this problem? At first look this problem might appear only in the case when you try to manipulate with EF context from multiple threads in parallel. But it is not a case, since you have await before each operator. – Maris Jul 03 '18 at 11:23
  • @Lukas Can you show us how you register DbContext in ASP.NET Core IoC container. Probably you have registered it as Singleton? If yes, then it is a source of an issue, you have to register it as Scoped or use .AddDbContext(...) method – Maris Jul 03 '18 at 11:26
  • The code sample you provided (as it is, functions called one after another with `await` keyword) should work. If you do something else and `await` keyword missed then you will get that exception. – Fabio Jul 03 '18 at 18:41
  • @Maris Its hard to extract only code that is needed to simulate that behavior, but I will try prepare some example. It is old .net framework 4.6 ASP.NET WebApi2 application, not .net core. There is used Unity as DI container, but instanciation of DbContext really is not as singleton. Its using hierarchical lifetime manager. – Lukas Jul 03 '18 at 21:35
  • @Lukas I don't know too much about Unity container and the hierarchical lifetime manager, but definitely the reason of that issue is - reusing the same context in parallel threads. Take a look here and try to register context per web request: https://stackoverflow.com/questions/5187562/mvc-ef-datacontext-singleton-instance-per-web-request-in-unity I think it should solve your problem. – Maris Jul 04 '18 at 08:26
  • @Lukas , BTW, do you really want to use Unity? Most of other popular IoC containers(like Castle Windsor, Autofac, Ninject...) have already a native support for Per Web request scope. – Maris Jul 04 '18 at 08:32
  • @Maris Solved, thanks a lot. Unity `HierarchicalLifetimeManager` is recomended for DB context injection, and when is everything synchronous, it works fine. But when I rewrite some methods as async, there was the same instance of Db context injected multiple times. Unity has per request lifetime manager, but its not working with OWIN (its using HttpContext). I know other containers like Autofac, but not enough to known if supports OWIN enviroment. For me is easier write my own OwinContextLifetimeManager for Unity. – Lukas Jul 05 '18 at 09:27

0 Answers0