向特定用户问题发送 SignalR 消息。我做错了什么?
Sending SignalR message to the specific user problem. What I am doing wrong?
首先,当我向所有客户端发送 SignalR 消息时,一切工作正常,其中:
public async Task SendMessage(GameStateModel game)
{
UpdateExistingGame(game);
await Clients.All.SendAsync("ReceiveMessage", game); //todo: send only to users in current game
}
在我的客户中:
public addGameStateListener = (): void => {
this.hubConnection.on('ReceiveMessage', (message: GameState) => {
if (message.gameId == this.game.gameState.gameId) {
this.game.setGame(message);
}
});
};
现在,当我试图将它发送给特定客户端时,我正在做这样的事情:
public async Task SendMessage(GameStateModel game) //todo: SendMessageAndUpdateCachedGame(GameStateModel game)
{
UpdateExistingGame(game);
await SendToUsersInGame(game);
}
private async Task SendToUsersInGame(GameStateModel game)
{
foreach (string user in game.PlayersNames)
{
if (!string.IsNullOrEmpty(user))
{
string id = await GetUserId(user);
await Clients.User(id).SendAsync("ReceiveMessage", game);
}
}
}
private async Task<string> GetUserId(string user) //from auth DB
{
return await _userService.GetUserId(user);
}
客户端代码仍然相同:
public addGameStateListener = (): void => {
this.hubConnection.on('ReceiveMessage', (message: GameState) => {
if (message.gameId == this.game.gameState.gameId) {
this.game.setGame(message);
}
});
};
注意 请注意,GetUserId
是从数据库中检索用户 ID,但它与 Context.User.Identity.Name
.
相同
我在客户端没有收到任何通知。问题是,在 documentation 中写道,在 hub 中它应该是:
public class MyHub : Hub
{
public void Send(string userId, string message)
{
Clients.User(userId).send(message);
}
}
这很令人困惑,因为没有 Send(string message)
这样的方法。我做错了什么?
UPDATE 基于 on this GitHub answer,当我尝试发送个人消息时:
foreach (string user in game.PlayersNames)
{
if (!string.IsNullOrEmpty(user))
{
string id = await GetUserId(user);
await Clients.Client(Context.ConnectionId).SendAsync("ReceiveMessage", game);
}
}
那么现在的问题是,如何获取每个用户的个体Context.ConnectionId
?
早些时候我试图解决同样的问题,所以我的客户有他的ID(在数据库和客户端相同),我添加了if语句,如if(this.client.id == received.id) => 做某事它工作正常。
好的,我解决了这个问题。根据问题更新,Context.ConnectionId
不同于 Context.User.Identity.Name
,您只能使用 Context.ConnectionId
.
进行单独的消息调用
所以我创建了缓存 Dictionary<string, string>
保存用户名和连接 ID:
public Dictionary<string, string> GetUserConnectionIdList()
{
if (!_cache.TryGetValue(CacheKeys.ConnectionIdList, out Dictionary<string, string> result))
{
result = new Dictionary<string, string>();
_cache.Set(CacheKeys.ConnectionIdList, result);
}
return result;
}
public void SetConnectionIdList(Dictionary<string, string> list)
{
_cache.Set(CacheKeys.ConnectionIdList, list);
}
public static class CacheKeys
{
public static string ConnectionIdList { get { return "_ConnectionIdList"; } }
}
接下来,在我的中心 class,OnConnectedAsync
我将新用户添加到字典,OnDisconnectedAsync
我从字典中删除用户:
public override async Task OnConnectedAsync()
{
string userName = await GetUserName(Context.User.Identity.Name);
string connectionId = Context.ConnectionId;
Dictionary<string, string> ids = _memoryAccess.GetUserConnectionIdList();
ids.Add(userName, connectionId);
_memoryAccess.SetConnectionIdList(ids);
}
public override async Task OnDisconnectedAsync(Exception ex)
{
string userName = await GetUserName(Context.User.Identity.Name);
string userDisplay = await GetUserDisplay(Context.User.Identity.Name);
Dictionary<string, string> ids = _memoryAccess.GetUserConnectionIdList();
ids.Remove(userName);
_memoryAccess.SetConnectionIdList(ids);
}
就是这样。现在我可以打个人电话了:
public async Task SendMessage(GameStateModel game)
{
UpdateExistingGame(game);
await SendToUsersInGame(game);
}
private async Task SendToUsersInGame(GameStateModel game)
{
foreach (string user in game.PlayersNames)
{
if (!string.IsNullOrEmpty(user))
{
string id = GetConnectionId(user);
await Clients.Client(id).SendAsync("ReceiveMessage", game);
}
}
}
private string GetConnectionId(string user)
{
Dictionary<string, string> ids = _memoryAccess.GetUserConnectionIdList();
return ids[user];
}
首先,当我向所有客户端发送 SignalR 消息时,一切工作正常,其中:
public async Task SendMessage(GameStateModel game)
{
UpdateExistingGame(game);
await Clients.All.SendAsync("ReceiveMessage", game); //todo: send only to users in current game
}
在我的客户中:
public addGameStateListener = (): void => {
this.hubConnection.on('ReceiveMessage', (message: GameState) => {
if (message.gameId == this.game.gameState.gameId) {
this.game.setGame(message);
}
});
};
现在,当我试图将它发送给特定客户端时,我正在做这样的事情:
public async Task SendMessage(GameStateModel game) //todo: SendMessageAndUpdateCachedGame(GameStateModel game)
{
UpdateExistingGame(game);
await SendToUsersInGame(game);
}
private async Task SendToUsersInGame(GameStateModel game)
{
foreach (string user in game.PlayersNames)
{
if (!string.IsNullOrEmpty(user))
{
string id = await GetUserId(user);
await Clients.User(id).SendAsync("ReceiveMessage", game);
}
}
}
private async Task<string> GetUserId(string user) //from auth DB
{
return await _userService.GetUserId(user);
}
客户端代码仍然相同:
public addGameStateListener = (): void => {
this.hubConnection.on('ReceiveMessage', (message: GameState) => {
if (message.gameId == this.game.gameState.gameId) {
this.game.setGame(message);
}
});
};
注意 请注意,GetUserId
是从数据库中检索用户 ID,但它与 Context.User.Identity.Name
.
我在客户端没有收到任何通知。问题是,在 documentation 中写道,在 hub 中它应该是:
public class MyHub : Hub
{
public void Send(string userId, string message)
{
Clients.User(userId).send(message);
}
}
这很令人困惑,因为没有 Send(string message)
这样的方法。我做错了什么?
UPDATE 基于 on this GitHub answer,当我尝试发送个人消息时:
foreach (string user in game.PlayersNames)
{
if (!string.IsNullOrEmpty(user))
{
string id = await GetUserId(user);
await Clients.Client(Context.ConnectionId).SendAsync("ReceiveMessage", game);
}
}
那么现在的问题是,如何获取每个用户的个体Context.ConnectionId
?
早些时候我试图解决同样的问题,所以我的客户有他的ID(在数据库和客户端相同),我添加了if语句,如if(this.client.id == received.id) => 做某事它工作正常。
好的,我解决了这个问题。根据问题更新,Context.ConnectionId
不同于 Context.User.Identity.Name
,您只能使用 Context.ConnectionId
.
所以我创建了缓存 Dictionary<string, string>
保存用户名和连接 ID:
public Dictionary<string, string> GetUserConnectionIdList()
{
if (!_cache.TryGetValue(CacheKeys.ConnectionIdList, out Dictionary<string, string> result))
{
result = new Dictionary<string, string>();
_cache.Set(CacheKeys.ConnectionIdList, result);
}
return result;
}
public void SetConnectionIdList(Dictionary<string, string> list)
{
_cache.Set(CacheKeys.ConnectionIdList, list);
}
public static class CacheKeys
{
public static string ConnectionIdList { get { return "_ConnectionIdList"; } }
}
接下来,在我的中心 class,OnConnectedAsync
我将新用户添加到字典,OnDisconnectedAsync
我从字典中删除用户:
public override async Task OnConnectedAsync()
{
string userName = await GetUserName(Context.User.Identity.Name);
string connectionId = Context.ConnectionId;
Dictionary<string, string> ids = _memoryAccess.GetUserConnectionIdList();
ids.Add(userName, connectionId);
_memoryAccess.SetConnectionIdList(ids);
}
public override async Task OnDisconnectedAsync(Exception ex)
{
string userName = await GetUserName(Context.User.Identity.Name);
string userDisplay = await GetUserDisplay(Context.User.Identity.Name);
Dictionary<string, string> ids = _memoryAccess.GetUserConnectionIdList();
ids.Remove(userName);
_memoryAccess.SetConnectionIdList(ids);
}
就是这样。现在我可以打个人电话了:
public async Task SendMessage(GameStateModel game)
{
UpdateExistingGame(game);
await SendToUsersInGame(game);
}
private async Task SendToUsersInGame(GameStateModel game)
{
foreach (string user in game.PlayersNames)
{
if (!string.IsNullOrEmpty(user))
{
string id = GetConnectionId(user);
await Clients.Client(id).SendAsync("ReceiveMessage", game);
}
}
}
private string GetConnectionId(string user)
{
Dictionary<string, string> ids = _memoryAccess.GetUserConnectionIdList();
return ids[user];
}