SignalR 和数据库上下文处理

SignalR and Database Context Disposals

我一直在尝试让 SignalR 启动数据库查询,然后根据所述查询的结果响应启动它的客户端。

但我已经 运行 进入 无法访问已处置的对象。 来自 DatabaseContext HubContext。我尝试了几种不同的方法来创建数据库控制器单例,none 其中有效。

我终于设法创建了一个解决方案,但现在想知道我是否创建了太多 instances/contexts 的数据库上下文。

这是我想出的方法。 (简体)

[Authorize(JwtBearerDefaults.AuthenticationScheme)]
public class Game : Hub
{
    private GameContext _dbContext;
    private IHubContext<Game> _hubContext;

    public Game(IHubContext<Game> hubContext)
    {
        _hubContext = hubContext;
    }

    public override async Task OnConnectedAsync()
    {
        await Clients.Client(Context.ConnectionId).SendAsync("DebugMessage", "Connected to Hub");
        await base.OnConnectedAsync();
    }

    public async void NewUser(string username, string userIdentifier)
    {
        _dbContext = new GameContext { };
        string connectionID = Context.ConnectionId;

        bool error = false;
        bool usernameExists = false;
        bool createdUser = false;

        try
        {
            var rows = await _dbContext.Users.Where(x => x.Username == username).ToListAsync();
            if (rows.Count > 0)
            {
                usernameExists = true;
                goto SendResponse;
            }
        }
        catch (Exception e)
        {
            error = true;
            goto SendResponse;
        }

        Users user = new Users { Username = username, UserIdentifier = userIdentifier, Joined = DateTime.UtcNow };
        try
        {
            _dbContext.Add(user);
            await _dbContext.SaveChangesAsync();
            createdUser = true;
            goto SendResponse;
        }
        catch (Exception e)
        {
            error = true;
            goto SendResponse;
        }

        SendResponse:
            await _hubContext.Clients.Client(connectionID).SendAsync("CreatedUser", username, usernameExists, createdUser, error);
    }

}

正如您在 NewUser 函数中看到的那样,我正在创建一个新的 instance/context 来使其正常工作。

感觉很浪费所以在游戏中心为它做了一个单例模式来检查它是否为空,如果需要的话创建一​​个新的,如下所示。

private Object padlock = new Object { };
private GameContext _dbContextInstance;
private GameContext _dbContext
{
    get
    {
        if (_dbContextInstance == null)
        {
            lock (padlock)
            {
                if (_dbContextInstance == null)
                {
                    _dbContextInstance = new GameContext { };
                }
            }
        }
        return _dbContextInstance;
    }
}

但它仍然感觉很浪费,因为当用户进行多次调用时,我不断地一遍又一遍地做同样的事情,它会加起来,所以在我继续之前,我想知道我是否走错了路如果是的话,我应该走哪条路。

谢谢

您的代码应如下所示

// this has to be a task, otherwise the framework
// cannot know when it has finished 
public async Task NewUser(string username, string userIdentifier)
{
    using (var dbContext = new GameContext())
    {
        string connectionID = Context.ConnectionId;

        bool error = false;
        bool usernameExists = false;
        bool createdUser = false;

        try
        {
            usernameExists  = await dbContext.Users.AnyAsync(x=> x.Username == username);
        }
        catch (Exception e)
        {
            error = true;
        }

        if (!usernameExists && !error)
        {
            Users user = new Users { Username = username, UserIdentifier = userIdentifier, Joined = DateTime.UtcNow };
            try
            {
                dbContext.Add(user);
                await dbContext.SaveChangesAsync();
                createdUser = true;
            }
            catch (Exception e)
            {
                error = true;
            }
        }

        await _hubContext.Clients.Client(connectionID).SendAsync("CreatedUser", username, usernameExists, createdUser, error);
    }
}

在 C# 中使用标签并不常见。您应该让框架负责连接(唯一重要的事情)的管理方式,这是通过正确使用 using 语句来完成的。