c# - SignalR and Database Context Disposals
问题描述
I have been trying to get SignalR to start a database query and then depending on the result of said query respond to the Client that initiated it.
But I have been running into Cannot access a disposed object. from both the DatabaseContext and HubContext. I have tried several different methods from creating a Database controller singleton amoung others, none of which worked.
I have finally managed to create a solution but am now wondering if I am creating too many instances/contexts of the Database context.
Here is the method I have come up with. (Simplified)
[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);
}
}
As you can see in the NewUser function I am creating a new instance/context to get it too work.
It feels like it's wasteful so have made a Singleton pattern for it in the Game Hub to check if its null and create a new one if needed as follows.
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;
}
}
But it still feels wasteful as I am continually making the same thing over and over when a User is making many calls it will add up so before I continue would like to know if I am going down the wrong route with this and if so what route i should be taking.
Thanks
解决方案
您的代码应如下所示
// 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
语句来完成。
推荐阅读
- r - 删除所有年份中特定日期之前的所有日期
- git - 在没有合并冲突的情况下拉入功能分支
- java - tablayout.newtab 空指针
- python - 如何将文件存储在 Windows 操作系统而不是 `/tmp` unix 中?
- html - 为什么设置很多数据时输入隐藏
- java - 我无法在宁静的 spring-boot 应用程序中发出 PUT 请求
- javascript - 为什么反应中的道具成为函数中的下一个参数返回一个函数
- powerbi - 需要调整 DAX 以在 Power BI 中显示正确的总数
- nginx - 在不绕过 AWS Cognito 的情况下反向代理到基于 VPC 的 AWS Elasticsearch 域
- amazon-web-services - 如何在自动缩放组中出现的 ecs 实例上启动新任务