I am trying to use SignalR with MVC4 c# project to send push notification to selected clients only.
For this I am using 'context.Clients.Client' by storing 'Context.ConnectionId' in c# static variable {since unable to use session with signalr}.
But since 'contextConnectionId' is a static variable; the message is still boardcasted to all clients :(
Is there any alternative to session with signal or any other elegant way to do this? (found few related post but no specific answers)
Code as below:
javaScript
$(document).ready(function (){
{
var chat = $.connection.PushNotify;
chat.client.addNewMessageToPage = function (type, message) {
if(type == "something")
{
alert(message);
}
}
// Start the connection.
$.connection.hub.start().done(function () {
chat.server.send($('').val(), $('').val());
});
)}
In c# HUB
[HubName("PushNotify")]
public class PushNotify : Hub
{
public void Send(string name, string message)
{
//assume its c# static variable
GlobalVariable.contextConnectionId = Context.ConnectionId;
}
}
public class PushNotification
{
public void SendMessage(string message, string type = "msg")
{
if (!string.IsNullOrEmpty(GlobalVariable.contextConnectionId))
{
var context = GlobalHost.ConnectionManager.GetHubContext<PushNotify>();
context.Clients.Client(GlobalVariable.contextConnectionId).addNewMessageToPage(type, message);
}
}
}
I don't think you example will work as expected. When you map your connection to your static variable you actually overwrite your static variable to the last connection which called Send method.
Each client connecting to a hub passes a unique connection id. You can
retrieve this value in the Context.ConnectionId property of the hub
context.
Which means your GlobalVariable.contextConnectionId
cannot be a simple string. You have to map your clients in a way, and every client is going to have a unique connection id. Perhaps a dictionary would be enough here, or own class containing more info. (i.e. browser info, IP adderss...)
(Quote is from this link) This should help you: http://www.asp.net/signalr/overview/guide-to-the-api/mapping-users-to-connections
EDIT
Providing a bit more information:
I believe the simplest solution for your question is to use groups. http://www.asp.net/signalr/overview/guide-to-the-api/working-with-groups
Your hub class would contain a method to join a group:
public Task JoinGroup(string groupName)
{
return Groups.Add(Context.ConnectionId, groupName);
}
public Task LeaveGroup(string groupName)
{
return Groups.Remove(Context.ConnectionId, groupName);
}
And let's say a PostMessage to group which sends to a given group only:
public void SendMessage(string groupName, string message, string type = "msg")
{
var context = GlobalHost.ConnectionManager.GetHubContext<PushNotify>();
context.Clients.Group(groupName).addNewMessageToPage(type, message);
}
When your clients join, they can connect to a group, and everything else will be handled by SignalR.
Joining the group from client and posting message:
var chat = $.connection.PushNotify;
$.connection.hub.start().done(function () {
chat.server.joinGroup("Group1");
chat.server.sendMessage("Group1", "Hi There");
});
Receiving messages is the same
chat.client.addNewMessageToPage = function (type, message) {
...
}
OTHER SOLUTION
Another solution could be using your own mapping or the SignalR Connection mapping. These solutions needs to override the OnConnected and OnDisconnected methods and map your connections. i.e.:
private readonly static ConnectionMapping<string> _connections =
new ConnectionMapping<string>();
public override Task OnConnected()
{
string name = Context.User.Identity.Name;
_connections.Add(name, Context.ConnectionId);
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
string name = Context.User.Identity.Name;
_connections.Remove(name, Context.ConnectionId);
return base.OnDisconnected(stopCalled);
}
public void SendChatMessage(string who, string message)
{
string name = Context.User.Identity.Name;
foreach (var connectionId in _connections.GetConnections(who))
{
Clients.Client(connectionId).addChatMessage(name + ": " + message);
}
}
Like in this example: http://www.asp.net/signalr/overview/guide-to-the-api/mapping-users-to-connections#inmemory