SignalR - 向所有人发送消息,排除用户的所有连接

时间:2014-01-11 23:07:27

标签: c# asp.net notifications signalr

在我的ASP.NET 4.5 WebForms项目中,我正在向当前连接的所有客户端发送更新通知。我所拥有的是两个集线器,其中一个向用户的其他打开的选项卡或窗口发送更新通知,另一个是向其他人发送更新通知。

第一个集线器就像

[Authorize]
public class SelfNotificationHub : Hub
{
    public void ShowSelfNotification(string page, string type, int id, string title)
    {
        string username = Context.User.Identity.Name;
        Clients.OthersInGroup(username).broadcastNotification(page, type, id, title);
    }

    public override Task OnConnected()
    {
        string name = Context.User.Identity.Name;
        Groups.Add(Context.ConnectionId, name);
        return base.OnConnected();
    }
}

这里我将添加由成员资格用户创建的所有connectionIds(来自每个创建的连接用户 - 制表符,窗口......),并将通知发送给除调用者之外的所有这些ID。来电者的通知由js代码显示。

另一个中心就像

[Authorize] 
public class NotificationHub : Hub
{
    public void ShowNotification(string page, string type, int id, string title)
    {
        string username = Context.User.Identity.Name;
        Clients.Others.broadcastNotification(username, page, type, id, title);
    }
}

在此我发送通知,包括用户名以通知其他用户。

问题是,通过此配置,用户的其他打开的选项卡和窗口正在接收来自两个集线器的通知。在第二个中心,我不能一起排除用户的connectionIds,如Clients.AllExcept(username)。 AllExcept函数需要类型“String [] ConnectionIds”,我无法弄清楚如何获取组中的connectionIds。这样,我可以从单个用户的组创建一个String []数组,并从该数组中排除callerId。这样做(我认为)。

我想我可以告诉我需要什么。如何在没有任何麻烦的情况下完成这种情况?

谢谢!

1 个答案:

答案 0 :(得分:4)

您应该更改Groups集合,以使用name作为键,将List作为值。

然后更改您的OnConnected()覆盖以查找name密钥,并添加或创建List<string> connectionId

在“自我”中心方法中,您需要与当前用户关联的所有连接:

List<string> clientWindows; 
Groups.TryGetValue(name, out clientWindows); 
clientWindows.ForEach(connectionId => {
    Clients.Client(connectionId)
         .broadcastNotification(username, page, type, id, title);
});

在您的“其他”中心方法中,您需要获取所有连接列表,但与该客户端名称关联的连接除外:

var others = Groups.Where(n => n.Key != name).SelectMany(s => s.Value);
Clients.AllExcept(others.ToArray())
    .broadcastNotification(username, page, type, id, title);

修改 这个答案假设Groups是一个全局定义的静态字典。

Dictionary<string, List<string>> Groups = new Dictionary<string, List<string>>()

要使其适应IGroupManager组,​​您需要创建静态字典以维护与用户关联的连接列表。这是代码:

using System.Collections.Generic;
using System.Linq;

private static Dictionary<string, List<string>> userGroups 
                                 = new Dictionary<string, List<string>>()
private static object _lock = new object();

public class NotificationHub : Hub
{
    public void ShowSelfNotification(string page, string type, int id, string title)
    {
        string username = Context.User.Identity.Name;
        Clients.Group(username).broadcastNotification(page, type, id, title);
    }

    public void ShowNotification(string page, string type, int id, string title)
    {
        string username = Context.User.Identity.Name;
        var others = userGroups.Where(n => n.Key != username)
                               .SelectMany(s => s.Value);

        Clients.AllExcept(others.ToArray())
               .broadcastNotification(username, page, type, id, title);
    }

    public override Task OnConnected()
    {
        string name = Context.User.Identity.Name;
        Groups.Add(Context.ConnectionId, name);

        lock(_lock)
        {
            if (userGroups .ContainsKey(name))
                userGroups [name].Add(Context.ConnectionId);
            else
                userGroups .Add(name, new List<string>{Context.ConnectionId})

        }

        return base.OnConnected();
    }

   public override Task OnDisconnected()
   {
       string name = Context.User.Identity.Name;
       lock(_lock)
       {
            if (userGroups .ContainsKey(name))
                userGroups[name].Remove(Context.ConnectionId);
       }
       return base.OnDisconnected();
   }
}