SignalR 从字典中添加/删除连接并从字典中查找组值 [英] SignalR Adding/Removing Connections from a dictionary and finding Group values from dictionary

查看:22
本文介绍了SignalR 从字典中添加/删除连接并从字典中查找组值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有登录到 asp.net 网站的组织,当每个成员登录时,我将他们的 ConnectionId 和 OrganizationId 添加到 SignalR Hub OnConnected 覆盖中名为 OrganizationMembers 的静态 ConcurrentDictionary.我这样做是为了将数据发送到包含仅与该组织(SignalR 组)相关的数据的页面回调函数.OrganizationId 将代表我向其发送数据的 SignalR 组.

I have Organizations that login to an asp.net website and when each member logs in I add their ConnectionId and OrganizationId to a static ConcurrentDictionary named OrganizationMembers in a SignalR Hub OnConnected override. I do this so I can send data to a page callback function that contains data relative only to that Organization (SignalR Group). The OrganizationId will represent the SignalR Group that I send data to.

同样在 OnConnnected 方法中,我将 OrganizationId 和 OrganizationId.ToString() 添加到另一个代表唯一组织 ID 的 ConcurrentDictionary.稍后我将解释为什么我存储 OrganizationId.ToString().我存储唯一的组织 ID,以便在调用方法并反复休眠的后台任务中,我可以枚举唯一的组织 ID,并仅发送与其相关的每个组织(SignalR 组)数据.

Also in the OnConnnected method, I add the OrganizationId and OrganizationId.ToString() to another ConcurrentDictionary that represents unique Organization Ids. I'll explain later why I store the OrganizationId.ToString(). I store unique Organization Ids so that in a background Task that calls a method and sleeps over and over, I can enumerate the unique Organization Ids and only send each Organization (SignalR Group) data relevant to it.

在 OnDisconnected 集线器覆盖中,删除连接后,我想检查 OrganizationMembers ConcurrentDictionary 中的 OrganizationId 值,以查看它是否是具有该 OrganizationId 的最后一个要断开连接的成员,如果是,则将其从 UniqueOrganizations 字典中删除.我知道字典 Values.Contains() 是 O(n) 所以我真的很想避免这种情况.

In the OnDisconnected Hub override, after I remove a Connection, I want to check the OrganizationId values in the OrganizationMembers ConcurrentDictionary to see if that was the last Member with that OrganizationId to disconnect and if so remove it from the UniqueOrganizations dictionary. I know the dictionary Values.Contains() is O(n) so I'd really like to avoid this.

这就是当任务枚举 UniqueOrganizations 时,不会有组织(SignalR 组)我试图不必要地向其发送数据,例如来自同一组织的 5 个成员登录但所有稍后关闭他们的浏览器,我不会尝试通过 SignalR 回调发送该组数据.

This is so when the task enumerates the UniqueOrganizations, there won't be Organizations (SignalR Groups) that I'm attempting to send data to needlessly in the case that say for example 5 Members from the same Organization log in but all later close their browser, I won't be attempting to send that Group data via the SignalR callback.

诚然,我不知道 SignalR 集线器的内部工作原理,因此如果我尝试将数据不必要地发送给已全部断开连接的组织成员(SignalR 组),这可能无关紧要.

Admittedly I don't know the internal workings of the SignalR Hub so it may be the case that it won't matter if I try to send data needlessly to Members of Organizations (SignalR Groups) that have all disconnected.

这是对 SignalR 集线器的过度思考吗?我是否应该不用担心确定最后一个组织(SignalR 组)成员是否已与集线器断开连接并且不从 UniqueOrganizations 中删除 OrganizationId?

Is this over-thinking the SignalR Hub? Should I not worry about determining if the last Organization (SignalR Group) Member has disconnected from the Hub and not remove the OrganizationId from the UniqueOrganizations?

如果这样做可以,我怎样才能避免字典 Values.Contains() 因为它是 O(n)?

If this is OK to do, how can I avoid the dictionary Values.Contains() since it's O(n)?

// the key is the ConnectionId of an Organization Member
// the value is the OrganizationId of the Member
protected static ConcurrentDictionary<string, int> _organizationMembers;
public static ConcurrentDictionary<string, int> OrganizationMembers {
    get {
        if(_organizationMembers == null) {
            _organizationMembers = new ConcurrentDictionary<string, int>();
        }

        return _organizationMembers;
    }
}

// the key is the OrganizationId to send the specific data to
// the value is the OrganizationId converted to string
protected static ConcurrentDictionary<int, string> _uniqueOrganizations;
public static ConcurrentDictionary<int, string> UniqueOrganizations {
    get {
        if(_uniqueOrganizations == null) {
            _uniqueOrganizations = new ConcurrentDictionary<int, string>();
        }

        return _uniqueOrganizations;
    }
}


// Hub Code

public override Task OnConnected() {
    string connectionId = Context.ConnectionId;
    string organizationId = Context.Request.QueryString["organizationId"];
    int organizationIdValue = int.Parse(organizationId);

    OrganizationMembers.TryAdd(connectionId, organizationIdValue);
    UniqueOrganizations.TryAdd(organizationIdValue, organizationId);

    // the organizationId represents the SignalR group
    Groups.Add(connectionId, organizationId);
    return base.OnConnected();
}


public override Task OnDisconnected() {
    string organizationId = string.Empty;
    int organizationIdValue;
    string connectionId = Context.ConnectionId;

    OrganizationMembers.TryRemove(connectionId, out organizationIdValue);

    // if that happens to be the last Member connection to be removed
    // then remove the OrganizationId from the unique OrganizationIds
    // so it won't be a wasted enumeration and useless callback

    // I want to avoid this O(n) Contains()
    if(!OrganizationMembers.Values.Contains(organizationIdValue)) {
        UniqueOrganizations.TryRemove(organizationIdValue, out organizationId);
    }

    Groups.Remove(connectionId, organizationId);
    return base.OnDisconnected();
}


// Task code
foreach(int organizationIdValue in DataCache.UniqueOrganizations.Keys) {
// this is why I also stored the OrganizationId as a string so I wouldn't have to
// convert it to a string each time the dictionary is enumerated.
// I can just have the organizationId string ready to use as the SignalR Group.
    string organizationId = UniqueOrganizations[organizationIdValue];

    try {
        string organizationData = GetOrganizationData(organizationIdValue);
        _clients.Group(organizationId).sendToOrganizationData(organizationData);
    }
    catch(Exception ex) {
        _clients.Group(organizationId).sendToOrganizationError();
    }
}

推荐答案

首先,SignalR 非常聪明,在发送到没有任何订阅的群组时不会浪费资源,所以只要发送到没有任何成员的群组就可以了因为这样做可以浪费几个周期.

First of all, SignalR is pretty smart about not wasting resources when sending to groups without any subscriptions, so you should be fine sending to groups without any members as long as it's OK to waste a few cycles doing that.

如果你没有太多的组织,你可以有一个 ConcurrentDictionary,其中 all 你的组织 ID 作为你的键和连接成员的数量作为你的价值.在 OnConnected 和 OnDisconnected 中可以分别使用 Interlocked.Increment 和 Interlocked.Decrement 来跟踪当前连接的成员.然后在您的任务中可以遍历密钥并跳过任何具有零连接成员的组织.

If you don't have too many organizations you can have a ConcurrentDictionary<int,int> with all your organization ids as your keys and the number of connected members as your value. In OnConnected and OnDisconnected in could use Interlocked.Increment and Interlocked.Decrement respectively to keep track of the currently connected members. Then in your task could loop over the keys and skip any organization with zero connected members.

如果您不介意调用 key.ToString(CultureInfo.InvariantCulture) 来获取组名,这个新的 ConcurrentDictionary 可以替换 _uniqueOrganizations.

This new ConcurrentDictionary could replace _uniqueOrganizations if you don't mind calling key.ToString(CultureInfo.InvariantCulture) to get the group name.

这篇关于SignalR 从字典中添加/删除连接并从字典中查找组值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆