如何在单例服务中使用数据库上下文?

gaa*_*kam 1 singleton entity-framework-core asp.net-core

我想将完成的国际象棋游戏存储在数据库中,以支持用户观看重播。

到目前为止,我有一个单例GameManager存储所有正在进行的游戏。因此,startup.cs我有以下代码行:

services.AddSingleton<IBattleManager, BattleManager>();
Run Code Online (Sandbox Code Playgroud)

现在,我想BattleManager访问DbContext保存已完成的游戏。

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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

是否有可能实现这一目标?怎么样?

尝试失败:

public class BattleManager : IBattleManager
{
    Data.ApplicationDbContext _context;
    public BattleManager(Data.ApplicationDbContext context)
    {
        _context = context;
    }
}
Run Code Online (Sandbox Code Playgroud)

这显然会失败,因为无法DbContext像这样将EF Core 注入到Singleton服务中。

我有一种模糊的感觉,我应该做这样的事情:

using (var scope = WhatDoIPutHere.CreateScope())
{
    var DbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
    DbContext.Replays.Add(new ReplayModel(...));
}
Run Code Online (Sandbox Code Playgroud)

这是正确的方向吗?

Sha*_*tin 5

您走在正确的轨道上。该IServiceScopeFactory能做到这一点。

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.
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

DbContext行为就像Transient在该using语句中具有作用域一样。

  • 我认为人们太执着于注入“IServiceProvider”作为反模式。他们的理由是,如果您更改 DI 容器,那么您就可以将其替换为容器提供的任何内容。坦率地说,归根结底,您需要解决问题并拥有工作代码并采用被视为“反模式”的依赖项似乎是最微小的担忧。此外,如果您要更换 DI 容器,您可能会到处进行大量的错误修复,直到它完全正常工作为止。我说不用担心。我没有。 (2认同)