3

I created a SignalR project. Want an application like basic whatsapp. I can send message to all clients with SignalR, but I can't send message to a specific user.

Here is what I tried.

Server side

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.MapSignalR();
    }
}

public class ChatHub : Hub
{
    public static string UserName = "";
    public void Send(string User, string Message)
    {
        //It doesn't works
        Clients.User(UserName).sendMessage(Message);
        //It works
        Clients.All.sendMessage(Message);
    }
    public override Task OnConnected()
    {
        //It works I get the UserName
        UserName = Context.QueryString["UserName"];
        return base.OnConnected();
    }
}

Client Side

protected override async void OnAppearing()
{
    chatHubConnection = new HubConnection("http://192.168.2.2:80/", new Dictionary<string, string>{
        { "UserName", myUser }
     });
    chatHubProxy = chatHubConnection.CreateHubProxy("ChatHub");
    chatHubProxy.On<string>("sendMessage", (k) => {
        Messages.Add(string.Format("Msg:{0}", k));
    });
    await chatHubConnection.Start();
}
private async void SendButton_Clicked(object sender, EventArgs e)
{
    await chatHubProxy.Invoke<string>("Send", recieverEntry.Text, messageEntry.Text);
}
Guest
  • 265
  • 2
  • 5
  • 13
  • You had a look here? http://stackoverflow.com/questions/19522103/signalr-sending-a-message-to-a-specific-user-using-iuseridprovider-new-2-0 – Ric Apr 07 '17 at 13:27
  • But your `UserName` is static so it will (assuming it works at all) hold the name of the last connected user, I don't think that is what you expect. – Evk Apr 07 '17 at 13:45
  • @Evk yes I know it, I created it for testing the code. – Guest Apr 07 '17 at 13:46

1 Answers1

6

Use ConnectionId to send message to specific client. UserId and UserName are different things, for more detail - https://learn.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/mapping-users-to-connections

Change your code to following (Ideally this Connections dictionary should be extracted as separate class to handle Username to Connection mapping)

public class ChatHub : Hub
{
    public static ConcurrentDictionary<string, string> Connections = new ConcurrentDictionary<string, string>();
    public void Send(string username, string message)
    {
        string connectionToSendMessage;
        Connections.TryGetValue(username, out connectionToSendMessage);

        if (!string.IsNullOrWhiteSpace(connectionToSendMessage))
        {
            Clients.Client(connectionToSendMessage).SendMessage(message);
        }
    }
    public override Task OnConnected()
    {
        if (!Connections.ContainsKey(Context.ConnectionId))
        {
            Connections.TryAdd(Context.QueryString["UserName"], Context.ConnectionId);
        }

        return base.OnConnected();
    }
}
Kaushal
  • 1,251
  • 1
  • 8
  • 8
  • thank you for your reply. But last user is not the user which I want to send the message. – Guest Apr 07 '17 at 15:38
  • 1
    @Guest you can send message to any user however you need connectionId of that user. Problem with your current code is, you using UserName. First issue, that function expect UserId (not UserName). Second, if you don't have userId then you can use ConnectionId on Client – Kaushal Apr 07 '17 at 15:44
  • 1
    @Guest you can map your user to connection. Options to do that https://learn.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/mapping-users-to-connections – Kaushal Apr 07 '17 at 15:56