0

In my web application I have a stateful object which needs to be the same between requests, so I register it as a singleton:

services.AddSingleton<IGamePlay, GamePlay.GamePlay>();

Now, somewhere down the line, GamePlay needs to consume a MyDbContext, and I add this using the following, because I need to pass in a specific constructor parameter of type DbContextOptions<MyDbContext>

services.AddDbContext<MyDbContext>(options => options.UseInMemoryDatabase(databaseName: "testdb"));

However, this fails at runtime with the following error:

InvalidOperationException: Cannot consume scoped service 'MyDbContext' from singleton 'IGamePlay'.

How do I register a dependency with AddDbContext that works with a singleton dependency?

EDIT: (In reply to the comments) I've found plenty of answers, but none that solve the problem. I've ended up registering MyDbContext using services.AddSingleton<MyDbContext>(new MyDbContext(new DbContextOptionsBuilder<MyDbContext>().UseInMemoryDatabase(databaseName: "testdb").Options));. It seems to work. Will something break horribly all of the sudden if I do it this way?

runeks
  • 1,745
  • 2
  • 17
  • 26
  • 3
    DbContexts are *NOT* meant to be single instance. That's already covered in the docs, articles and multiple duplicate questions about scoped services - register a factory instead of the DbContext instance itself – Panagiotis Kanavos Dec 04 '18 at 11:43
  • See also: https://stackoverflow.com/questions/50788272/how-to-instantiate-a-dbcontext-in-ef-core – Stefan Dec 04 '18 at 11:44
  • 1
    Too many duplicates already, you need to do a little more research. For example, I found the duplicate Googling "asp.net core singlenton and dbcontext" – Camilo Terevinto Dec 04 '18 at 11:45
  • @CamiloTerevinto some of those duplicates give bad advice: `Just make it a singleton`. The accepted answer in the question you linked as duplicate isn't exactly the best - it weakens DI by injects the DbOptions and constructing the DbContext in the constructor. – Panagiotis Kanavos Dec 04 '18 at 11:48
  • 1
    @PanagiotisKanavos Thanks, I've added some better duplicates. There's no DI way to do this correctly, though, since this scenario is not solvable by DI – Camilo Terevinto Dec 04 '18 at 11:52
  • @runeks yes, your code now is broken. You have a *singleton* that will keep caching entities for as long as the application runs. That may work for testing with in-memory repos, but is essentially a memory leak for long-running production code hitting a real database. The cached entities will eventually get stale too. The duplicates answers how to fix this. Either create a scope, or pass a factory function/instance to the constructor – Panagiotis Kanavos Dec 04 '18 at 12:41
  • @runeks if you want a *memory cache* there are far better options than using EF. A simple ConcurrentDictionary would do. – Panagiotis Kanavos Dec 04 '18 at 12:42

0 Answers0