【问题标题】:Sending SignalR message to the specific user problem. What I am doing wrong?向特定用户问题发送 SignalR 消息。我做错了什么?
【发布时间】:2021-02-27 10:52:49
【问题描述】:

首先,当我向所有客户端发送 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 中写的是,在集线器中它应该是:

public class MyHub : Hub
{
    public void Send(string userId, string message)
    {
        Clients.User(userId).send(message);
    }
}

这很令人困惑,因为没有像Send(string message) 这样的方法。我做错了什么?

更新基于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

【问题讨论】:

    标签: c# angular signalr asp.net-core-2.2


    【解决方案1】:

    之前我试图解决同样的问题,所以我的客户有他的 id(在 db 和客户端相同),我添加了 if 语句,如 if(this.client.id == received.id) => do smth .它工作正常。

    【讨论】:

    • 我应该把if(this.client.id == received.id) =&gt; do smth放在哪里?在集线器或客户端代码中?你从哪里获取received.idthis.client.id 来自哪里?
    • @bakunet 尝试将其更改为: private async Task SendToUsersInGame(GameStateModel game) { foreach (string user in game.PlayersNames) { if (!string.IsNullOrEmpty(user)) { string id = await获取用户ID(用户);等待 Clients.All.SendAsync("ReceiveMessage", game); } } } 然后检查客户端,如果它有 id,如果 (message.gameId == this.game.gameState.gameId) { this.game.setGame(message);
    • @bakunet 我不认为这是最佳决定,但如果您只需要一个可行的解决方案,请尝试一下
    【解决方案2】:

    好的,我解决了这个问题。根据问题更新,Context.ConnectionIdContext.User.Identity.Name 不同,您只能使用 Context.ConnectionId 进行单独的消息呼叫。

    所以我创建了缓存 Dictionary&lt;string, string&gt; 保存用户名和连接 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"; } }
    }
    

    接下来,在我的 hub 类中,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];
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-30
      • 2016-09-19
      • 2017-12-28
      • 2015-04-27
      • 1970-01-01
      相关资源
      最近更新 更多