Reputation: 2982
I can't make works the message sending to one specific user from the code behind. Clients.All
works, Clients.AllExcept(userId)
works, but not Client.User(userId)
.
My hub:
public class MessagingHub : Hub
{
public override Task OnConnected()
{
var signalRConnectionId = Context.ConnectionId;
// for testing purpose, I collect the userId from the VS Debug window
System.Diagnostics.Debug.WriteLine("OnConnected --> " + signalRConnectionId);
return base.OnConnected();
}
}
My controller to send message from code behind:
public void PostMessageToUser(string ConnectionId)
{
var mappingHub = GlobalHost.ConnectionManager.GetHubContext<MessagingHub>();
// doesn't works
mappingHub.Clients.User(ConnectionId).onMessageRecorded();
// doesn't works
mappingHub.Clients.Users(new List<string>() { ConnectionId }).onMessageRecorded();
// works
mappingHub.Clients.All.onMessageRecorded();
// works (?!)
mappingHub.Clients.AllExcept(ConnectionId).onMessageRecorded();
}
How my hub is initialized on the JS:
var con, hub;
function StartRealtimeMessaging()
{
con = $.hubConnection();
hub = con.createHubProxy('MessagingHub');
hub.on('onMessageRecorded', function () {
$(".MessageContainer").append("<div>I've received a message!!</div>");
});
con.start();
}
And finally how I send a(n empty) message to the hub:
function TestSendToUser(connectionId)
{
$.ajax({
url: '/Default/PostMessageToUser',
type: "POST",
data: { ConnectionId: connectionId},// contains the user I want to send the message to
});
}
So, it works perfectly with mappingHub.Clients.All.onMessageRecorded();
but not with mappingHub.Clients.User(ConnectionId).onMessageRecorded();
or mappingHub.Clients.Users(new List<string>() { ConnectionId}).onMessageRecorded();
.
But interestingly, it works with mappingHub.Clients.AllExcept(ConnectionId).onMessageRecorded();
: All users connected receive the message except the given userid, which means the userid is good, and the user is well identified. So, why Clients.User(ConnectionId)
doesn't works?
Upvotes: 3
Views: 3263
Reputation: 31
I face same problem.
I change from:
Clients.User(connectionId).SendAsync(CallbackDefinition.DirectMessage, directMessageResult);
to:
Clients.Client(connectionId).SendAsync(CallbackDefinition.DirectMessage, directMessageResult);
And it work :D
Thank to: Matthieu Charbonnier
Upvotes: 0
Reputation: 2982
If you want to send a message to one particular connection and when you want to use the ConnectionId
, make sure you use Clients.Client
, and not Clients.User
Like this:
public void PostMessageToUser(string connectionId)
{
var mappingHub = GlobalHost.ConnectionManager.GetHubContext<MessagingHub>();
// Like this
mappingHub.Clients.Client(connectionId).onMessageRecorded();
// or this
mappingHub.Clients.Clients(new List<string>() { connectionId }).onMessageRecorded();
}
Upvotes: 5
Reputation: 137
I had the same problem. I couldn't get .User(ConnectionId) to work.
I have just spent days trying to get SignalR to report progress on a long processing job to only the client who requested the job. That is, it isn't a chat app which most of the examples describe.
Any 'long processing progress reporting' examples I found only have a sim of the job in the hub. I have a controller doing real work and need to send messages from the controller, not the hub.
I used this answer https://stackoverflow.com/a/21222303/3251300. as a workaround for your stated problem but have included all the code snippets I use for the long processing job in case they are useful for anyone who stumbles on this answer.
The workaround has an elegance in that it uses the .Group() feature. By setting each groupID equal to the internal userID, messages can be sent using .Group(userID) without having to separately maintain a list of the userID/connectionID relationships outside SignalR.
There may be a way to maintain the relationships in SignalR without using the .Group() feature but I haven’t found it yet.
Pass the userID to the view using a hidden type which then makes it available to the js.
<input type="hidden" value="@ViewBag.UserID" id="userID" />
Then in the js hub script use the following to send the userID to the hub when the hub connection starts up.
$.connection.hub.start()
.done(function () {
var userID = document.getElementById('userID').value;
$.connection.myHub.server.announce(userID);
})
.fail(function () { alert("Hub failed to start.") });
The hub then has one statement which associates the userID and connectionID to the groupID, which is then the same string as the userID.
public class MyHub : Hub
{
public void Announce(string userID)
{
Groups.Add(Context.ConnectionId, userID);
}
}
To send messages from the controller (Again, not the hub in this case, the message is reporting progress to the client on a long processing request running in the controller) after setting the hub context, use .Group() and the internal userID.
var hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
string fileMessage = "Some message";
hubContext.Clients.Group(userID).hubMessage(fileMessage);
This is then displayed in the view using the js to place the message in a div
$.connection.myHub.client.hubMessage = function (message) {
$("#hubMessages").html(message);
}
'#hubMessages' refers to this div in the view. Examples use .append which makes the div grow each time you send a message, .HTML replaces whatever is in the div with the new message.
<div id="hubMessages"></div>
Anyone who comes to this answer and is trying to get going on MVC and SignalR, a big shout out to Caleb who has a great series of intro vids for SignalR https://youtu.be/kr8uHeNjOKw Anyone who finds this answer who is new to SignalR I recommend you spend an hour watching these.
Upvotes: 4