1
votes

I am trying to create a .net core 3.0 SignalR project with Angular as client app. I have established a successful connection between client and server and send messages to all the connected clients. I intend to send messages to a particular user and not to all the connected clients. To achieve that I trying to work with ConnectionId, UserIdentifier and User.Identity.Name.

My server side code/Message Hub

namespace SignalR_server
{
    public class MessageHub : Hub
    {
        public static ConcurrentDictionary<string, string> MyUsers = new ConcurrentDictionary<string, string>();

        public override Task OnConnectedAsync()
        {
            string name = Context.User.Identity.Name;
            MyUsers.TryAdd( Context.ConnectionId,name);
            return base.OnConnectedAsync();
        }

        public override Task OnDisconnectedAsync(Exception exception)
        {
            string garbage;
            MyUsers.TryRemove(Context.ConnectionId, out garbage);
            return base.OnDisconnectedAsync(exception);
        }

        public void Send(string msg)
        {
            string strMessage = string.Empty;

            Clients.All.SendAsync("transfermessage",strMessage);
        }

        public string GetConnectionID()
        {
            return Context.ConnectionId;
        }

        public string GetUserIdentifier()
        {
            return Context.UserIdentifier;
        }

        public string GetUserName()
        {
            return Context.User.Identity.Name;
        }

        public Task SendPrivateMessage(string user, string message)
        {
            return Clients.Users(user).SendAsync("transfermessage1", message);

        }
    }
}

Client side / Angular code

public startConnection = () => {
    this.hubConnection = new signalR.HubConnectionBuilder()
                            .withUrl('https://localhost:44363/message',{
                              skipNegotiation: true,
                              transport: signalR.HttpTransportType.WebSockets
                            })
                            .build();

    this.hubConnection
        .start()
        .then(() => {
          console.log('Connection Started')
          console.log('Connection ID: ')
          console.log(this.hubConnection.invoke("GetConnectionID"))
          console.log('User Identifier: ')
          console.log(this.hubConnection.invoke("GetUserIdentifier"))
          console.log('User Name: ')
          console.log(this.hubConnection.invoke("GetUserName"))
          // console.log(this.hubConnection.invoke("SendPrivateMessage","Myuser","test message"))
      })
        .catch(err => console.log('Error while connecting: ' + err))
  }

Whenever a new client is connected, I can see a value for connectionId but UserIdentifier,User.Identity.Name comes out to be null.

enter image description here

I am not sure why is this happening; am I missing some thing or is something is to be done to define UserIdentifers?

2
why is the question downvoted ? - cvg
have you resolved this? - Ismail Umar
Haven't solved, but I guess authorizations will be required to use UserIdentifiers. I have used groups instead of users for my use case - cvg
Yes, Authorization is required to use the user IDs and all. However, U need to implement the IUserIdProvuder to get access to the ids - Ismail Umar
I will post a method shortly - Ismail Umar

2 Answers

2
votes

In my opinion you need to specify the [Auhtorize] attribute to the Hubs class you create and as well implement the IUserIdProvider then register it in the Startup.cs class.

1. Do this on the Hub:

[Authorize]
public class MessageHub : Hub
{
  // Code removed for brevity
}

2. Implement the IUserIdProvider for UserId or Name or Email as You would Like

public class IdBasedUserIdProvider : IUserIdProvider
 {
      public string GetUserId(HubConnectionContext connection)
      {
           //TODO: Implement USERID Mapper Here
           //throw new NotImplementedException();

           return connection.User.FindFirst("sub").Value;
      }
 }

3. Register the Provider in the Startup.cs class

public void ConfigureServices(IServiceCollection services)
{
     services.AddSignalR();
     services.AddSingleton<IUserIdProvider, IdBasedUserIdProvider>();
}

I hope this helps you resolve the issue you are having

-1
votes

add [Authorize] attribute on public class MessageHub : Hub the class should now be

[Authorize]
public class MessageHub : Hub