.net-coresignalrasp.net-core-signalr

Signalr outer calls for separate client


I'm getting message receiving from outer service in controller, with username. I need to separate clients, but can't get connectionId in controller: hubContext.Clients.Client(connectionId).SendAsync.. What is the best way to separate calls in Signalr by clients, in .net-core?

I tried calling from controller in js then back again with connectionId, but there is no separator in controller - hubContext.Clients.All.SendAsync.. I also tried to set up hub for outer calls, but can't. I'm new in Signalr, need a little help. Thanks


Solution

  • Actually, there is no need to get the conection ID for each user.

    According to this document for user in SignalR.

    A single user in SignalR can have multiple connections to an app. For example, a user could be connected on their desktop as well as their phone. Each device has a separate SignalR connection, but they're all associated with the same user. If a message is sent to the user, all of the connections associated with that user receive the message. The user identifier for a connection can be accessed by the Context.UserIdentifier property in the hub.

    By default, SignalR uses the ClaimTypes.NameIdentifier from the ClaimsPrincipal associated with the connection as the user identifier.

    So if you want to identity each user ,you should have the authentication schema, like identity.

    Then you could directly using the identity user's name to send the message to specific user.

    Like below:

    public Task SendPrivateMessage(string user, string message)
    {
        // the user is the ClaimTypes.NameIdentifier 
        return Clients.User(user).SendAsync("ReceiveMessage", message);
    }
    

    Also if you don't want to use the ClaimTypes.NameIdentifier to let the signalr bind to the connection ID, you could customize it.

    Like this, this is using the Email instead of the NameIdentifier to bind with it.

    public class EmailBasedUserIdProvider : IUserIdProvider
    {
        public virtual string GetUserId(HubConnectionContext connection)
        {
            return connection.User?.FindFirst(ClaimTypes.Email)?.Value!;
        }
    }
    

    And register it inside the program.cs :

    builder.Services.AddSingleton<IUserIdProvider, EmailBasedUserIdProvider>();