Reputation:
I would like to store completed chess games in the database to support users watching replays.
So far I have a singleton GameManager
that stores all ongoing games. So within startup.cs
I have the following line of code:
services.AddSingleton<IBattleManager, BattleManager>();
Now I would like to have BattleManager
access the DbContext
to save completed games.
public class BattleManager : IBattleManager
{
//...
private void EndGame(ulong gameId)
{
var DbContext = WhatDoIPutHere?
lock(gameDictionary[gameId])
{
DbContext.Replays.Add(new ReplayModel(gameDictionary[gameId]));
gameDictionary.Remove(gameId)
}
}
}
Is it possible to anyhow achieve this? How?
Failed attempts:
public class BattleManager : IBattleManager
{
Data.ApplicationDbContext _context;
public BattleManager(Data.ApplicationDbContext context)
{
_context = context;
}
}
This will clearly fail since one cannot inject EF Core DbContext
into a Singleton service like that.
I have a vague feeling that I should do something of this kind:
using (var scope = WhatDoIPutHere.CreateScope())
{
var DbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
DbContext.Replays.Add(new ReplayModel(...));
}
Is this the right direction?
Upvotes: 7
Views: 4050
Reputation: 141512
You're on the right track. The IServiceScopeFactory
can do that.
public class BattleManager : IBattleManager {
private readonly IServiceScopeFactory scopeFactory;
public BattleManager(IServiceScopeFactory scopeFactory)
{
this.scopeFactory = scopeFactory;
}
public void MyMethod() {
using(var scope = scopeFactory.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<DbContext>();
// when we exit the using block,
// the IServiceScope will dispose itself
// and dispose all of the services that it resolved.
}
}
}
The DbContext
will behave like it has a Transient
scope within that using
statement.
Upvotes: 13