向特定用户问题发送 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];
}