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

时间:2018-08-20 22:48:50

标签: asp.net-core singleton entity-framework-core

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

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

services.AddSingleton<IBattleManager, BattleManager>();

现在,我想让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)
        }
    }
}

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

尝试失败:

public class BattleManager : IBattleManager
{
    Data.ApplicationDbContext _context;
    public BattleManager(Data.ApplicationDbContext context)
    {
        _context = context;
    }
}

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

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

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

这是正确的方向吗?

1 个答案:

答案 0 :(得分:3)

您在正确的轨道上。 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.
        }
    }
}

DbContext的行为就像在该Transient语句中具有using范围一样。