如何将消息发送到保存在AspNetUsers表Signal R中的用户ID

时间:2020-01-22 06:38:12

标签: asp.net-core signalr signalr-hub

我正在尝试发送消息。我尝试连接ID

public Task SendMessaageToConnectionID(string ConnectionID,string Message)
{
    return Clients.Clients(ConnectionID).SendAsync("RecieveMessage", Message);
}

成功完成 现在我正在尝试

public Task SendMessageToUser(string userId,string Message)
{
    return Clients.Clients(userId).SendAsync(Message);
}

我正在发送保存在AspNetUser表中的用户的用户ID

How Can I send this to a User ID or is there any other way except connection id to send the message to user?

1 个答案:

答案 0 :(得分:1)

SignalR不会为我们存储UserId-ConnectionId映射。我们需要自己做。例如,当某些用户建立与集线器的连接时,它应触发ReJoinGroup()方法。

此外,为了确保Groups属性正常运行,您还需要:

  • 调用RemoveFromGroupAsync删除旧的<connectionId, groupName>映射
  • 调用AddToGroupAsync以添加新的<connectionId, groupName>映射。

通常,您可能希望将这些信息存储在Redis或RDBMS中。为了进行测试,我创建了一个演示,将这些映射存储在内存中供您参考:

public class MyHub:Hub
{
    /// a in-memory store that stores the <userId, connectionId> mappings
    private Dictionary<string, string> _userConn = new Dictionary<string,string>();
    private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);

    public override async Task OnConnectedAsync()
    {
        // get the real group Name by userId, 
        //     for testing purpose, I use the userId as the groupName, 
        //         in your scenario, you could use the ChatRoom Id
        var groupName = Context.UserIdentifier;
        await this.ReJoinGroup(groupName);
    }

    // whenever a connection is setup, invoke this Hub method to update the store
    public async Task<KeyValuePair<string,string>> ReJoinGroup(string groupName)
    {
        var newConnectionId = Context.ConnectionId;
        var userId = Context.UserIdentifier;
        await this._semaphore.WaitAsync();
        try{
            if(_userConn.TryGetValue(userId, out var oldConnectionId))
            {
                _userConn[userId]= newConnectionId;
                // remove the old connectionId from the Group
                if(!string.IsNullOrEmpty(groupName)){
                    await Groups.RemoveFromGroupAsync(oldConnectionId, groupName);
                    await Groups.AddToGroupAsync(newConnectionId, groupName);
                }
            } else {
                _userConn[userId]= newConnectionId;
                if(!string.IsNullOrEmpty(groupName)){
                    await Groups.AddToGroupAsync(newConnectionId, groupName);
                }
            }
        } finally{
            this._semaphore.Release();
        }
        return new KeyValuePair<string,string>(userId, newConnectionId); 
    }

    /// your SendMessageToUser() method
    public async Task SendMessageToUser(string userId,string Message)
    {
        // get the connectionId of target user
        var userConn = await this.GetUserConnection(userId); 
        if( userConn.Equals(default(KeyValuePair<string,string>))) {
            throw new Exception($"unknown user connection with userId={userId}");
        }
        await Clients.Clients(userConn.Value).SendAsync(Message);
    }


    /// a private helper that returns a pair of <UserId,ConnectionId>
    private async Task<KeyValuePair<string,string>> GetUserConnection(string userId)
    {
        KeyValuePair<string,string> kvp = default;
        string newConnectionId = default;
        await this._semaphore.WaitAsync();
        try{
            if(this._userConn.TryGetValue(userId, out newConnectionId)){
                kvp= new KeyValuePair<string, string>(userId, newConnectionId);
            }
        } finally{
            this._semaphore.Release();
        }
        return kvp;
    }

}