简体   繁体   English

SignalR 将用户 ID 从 controller 映射到连接 ID

[英]SignalR mapping User Id to Connection Id from controller

I am building an ASP.NET Core application with Angular, and I am trying to implement a basic, one-on-one chat functionality using SignalR.我正在使用 Angular 构建一个 ASP.NET Core 应用程序,我正在尝试使用 SignalR 实现基本的一对一聊天功能。

Since I want to allow one-on-one chatting and make chat messages persistent at some point, I'd like to be able to map User Id to SignalR Connection Id and send messages directly to a user based on their Id.因为我想允许一对一聊天并在某个时候使聊天消息持久化,所以我希望能够将 map 用户 ID 转换为 SignalR 连接 ID,并根据用户的 ID 直接向用户发送消息。

Now, all the examples I've seen use code within a Hub, which makes sense since Hub keeps track of Clients and their connection ids.现在,我看到的所有示例都使用 Hub 中的代码,这是有道理的,因为 Hub 会跟踪客户端及其连接 ID。 But other logic that I'll have starts and ends inside my Controller, of course, and I can't call a hub directly from a controller.但是我的其他逻辑在我的 Controller 中开始和结束,当然,我不能直接从 controller 调用集线器。

Since SignalR is supposed to be relying on Identity by default, his is what I've tried so far:由于默认情况下 SignalR 应该依赖于 Identity,因此到目前为止我已经尝试过:

[Route("send")]
    [HttpPost]
    public async Task<IActionResult> SendRequest([FromBody] Chat.Models.Message message)
    {
        var userId = Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)); // I'd like to register this (current) userId with SignalR connection Id somehow
        
        var sender = new ChatSender { Id= userId, Name = user.FullName };

        await _hubContext.Clients.All.SendAsync("ReceiveMessage", sender, message.MessageText); // can't extend this, nor access hub directly

        //var recipient = _hubContext.Clients.User(message.To); // message.To is a Guid of a recepient
        //await recipient.SendAsync("ReceiveMessage", sender, message.MessageText);
        return Ok();
    }

The code above works as a broadcast, but if I replace the _hubContext.Clients.All.SendAsync with two commented out lines below, it does nothing.上面的代码作为广播工作,但如果我用下面的两条注释掉的行替换_hubContext.Clients.All.SendAsync ,它什么都不做。

Any suggestions?有什么建议么?

SignalR mapping User Id to Connection Id SignalR 将用户 ID 映射到连接 ID

To map the user id /name with the connection id, you need to use the Hub's OnConnectedAsync method to get the userid/username and the connection id, then insert them into database. map 用户id/name 和connection id,需要使用Hub 的OnConnectedAsync方法获取userid/username 和connection id,然后将它们插入到数据库中。 Code like below:代码如下:

[Authorize]
public class ChatHub : Hub
{
    private readonly ApplicationDbContext _context;
    public ChatHub(ApplicationDbContext context)
    {
        _context = context;
    }
    public override async Task OnConnectedAsync()
    {
        //get the connection id
        var connectionid = Context.ConnectionId;
        //get the username or userid
        var username = Context.User.Identity.Name;
        var userId = Guid.Parse(Context.User.FindFirstValue(ClaimTypes.NameIdentifier));

        //insert or updatde them into database.
        var CId = _context.UserIdToCId.Find(userId);
        CId.ConnectionId = connectionid;
        _context.Update(CId);
        await _context.SaveChangesAsync();
        await base.OnConnectedAsync();
    }

map User Id to SignalR Connection Id and send messages directly to a user based on their Id. map User Id 到 SignalR Connection Id 并根据他们的 Id 直接向用户发送消息。

You can pass your receiver id or name from your client to the SendRequest method, according to the receiver id or name to find the signalr connection id from database.您可以将您的接收者 ID 或名称从您的客户端传递给SendRequest方法,根据接收者 ID 或名称从数据库中找到 signalr 连接 ID。 After find the receiver's connection id, then use the following code to send message:找到接收者的连接 ID 后,然后使用以下代码发送消息:

await _hubContext.Clients.Client("{receiver connection id}").SendAsync("ReceiveMessage", message);

the more code you can refer to:更多代码可以参考:

 public class HomeController : Controller
    {
        private readonly IHubContext<ChatHub> _hubContext;
        private readonly ApplicationDbContext _context;
        public HomeController( IHubContext<ChatHub> hubContext, ApplicationDbContext context)
        {               
            _hubContext = hubContext;
            _context = context;
        }
         ...
        /// <summary>
        /// 
        /// </summary>
        /// <param name="receiver">receiver id or name</param>
        /// <param name="message">message </param>
        /// <returns></returns>
        [Route("send")]
        [HttpPost]
        public async Task<IActionResult> SendRequest([FromBody] string receiver, Message message)
        {
            //1. according to the receiver id or name to find the signalr connection id
                //To map the user id /name with the connection id, you need to use the Hub's OnConnectedAsync method to get the userid/username and the connection id.
                //then insert them into database
            //2. After find the receiver's connection id, then use the following code to send message.
            await _hubContext.Clients.Client("{receiver connection id}").SendAsync("ReceiveMessage", message);
             
            return Ok();
        } 

Note When the receiver is disconnected,remember to delete the receiver's connection id from database, avoid sending error.注意当接收方断开连接时,记得从数据库中删除接收方的连接ID,避免发送错误。

Besides, you can refer to How can I make one to one chat system in Asp.Net.Core Mvc Signalr?另外可以参考How can I make one to one chat system in Asp.Net.Core Mvc Signalr? to know more.了解更多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM