Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use SignalR to send data to a specific user?

I have a client which receives messages over SignalR. It is working great but it is more like a broadcast. I would like to be able to send messages to a specific client. On the client-side I have a userId and I set up my connection like this:

const userId = getUserId();

if (userId) {
    const beacon = new signalR.HubConnectionBuilder()
        .withUrl(`${URL}/api?userId=${userId}"`)
        .build();

    beacon.on('newMessage', notification => console.log);
    beacon.start().catch(console.error);
  }
};

On the server-side (Azure Function written in JavaScript) I have a message and a userId. The question for me is how does the server know which SignalR connection is going to this specific user? Can I somehow tell SignalR who I am?

like image 579
leonheess Avatar asked Oct 30 '19 17:10

leonheess


2 Answers

Using the Azure SignalR Service and the client-side code from the question I was able to get it to work. I used the following Azure Function to negotiate the connection:

module.exports = async function (context, req, connectionInfo) {
  context.res.body = connectionInfo;
  context.done();
};

{
  "disabled": false,
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    },
    {
      "type": "signalRConnectionInfo",
      "name": "connectionInfo",
      "userId": "{userId}",             // <----- IMPORTANT PART!
      "hubName": "chat",
      "direction": "in"
    }
  ]
}

As well as another function to send a message to a specific user:

module.exports = async function (context, req) {
  const messageObject = req.body;
  return {
    "target": "newMessage",
    "userId": messageObject.userId,
    "arguments": [ messageObject.message]
  };
};

{
  "disabled": false,
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    },
    {
      "type": "signalR",
      "name": "$return",
      "hubName": "chat",
      "direction": "out"
    }
  ]
}
like image 72
leonheess Avatar answered Oct 25 '22 06:10

leonheess


If you are using Azure SignalR Service:

module.exports = async function (context, req) {
    context.bindings.signalRMessages = [{
        // message will only be sent to this user ID
        "userId": "userId1",
        "target": "newMessage",
        "arguments": [ req.body ]
    }];
};

One userId could map to multiple client connections (e.g. devices), be aware of that.

If you need to send messages to multiple users or are hosting SignalR yourself:

Groups are the easiest way to send messages to a subset of users. If you want to send a message to a certain user, you can use the userId as the name of the group.

Deciding which user belongs to which group is a server-side feature, so you need to write some code.

module.exports = async function (context, req) {
  context.bindings.signalRGroupActions = [{
    "userId": req.query.userId,
    "groupName": "myGroup",
    "action": "add"
  }];
};
like image 35
Alex AIT Avatar answered Oct 25 '22 05:10

Alex AIT