我有組織登錄到一個asp.net網站,並且當每個成員登錄時,我將它們的ConnectionId和OrganizationId添加到名爲OrganizationMembers的靜態ConcurrentDictionary在SignalR Hub OnConnected覆蓋。我這樣做,所以我可以發送數據到頁面回調函數,其中包含僅相關組織(SignalR組)的數據。 OrganizationId將代表我發送數據的SignalR組。SignalR從字典中添加/刪除連接並從字典中查找組值
同樣在OnConnnected方法中,我將OrganizationId和OrganizationId.ToString()添加到另一個表示唯一Organization ID的ConcurrentDictionary。稍後我會解釋爲什麼我存儲OrganizationId.ToString()。我存儲了獨特的組織ID,因此在後臺調用方法並一遍又一遍地睡眠的任務中,我可以枚舉唯一的組織ID,並只發送與其相關的每個組織(SignalR組)數據。
在OnDisconnected Hub覆蓋中,我刪除連接後,我想檢查OrganizationMembers ConcurrentDictionary中的OrganizationId值,以查看是否具有該斷開連接的OrganizationId的最後一個成員,如果是這樣,則將其從UniqueOrganizations字典中刪除。我知道字典Values.Contains()是O(n),所以我真的想避免這種情況。
這是這樣的,當任務枚舉UniqueOrganizations時,不會有組織(SignalR組)(我試圖發送數據給不必要的組織),例如說來自同一組織的5個成員登錄但後來都關閉了瀏覽器,我不會試圖通過SignalR回調來發送該組數據。
不可否認的是,我不知道SignalR Hub的內部工作原理,因此,如果我嘗試不必要地將數據發送給所有已斷開連接的組織成員(SignalR組),這無關緊要。
這是否過度思考SignalR Hub?我是否應該不擔心確定最後一個組織(SignalR Group)成員是否從Hub中斷開連接,並且不從UniqueOrganizations中移除OrganizationId?
如果這是可以做的,我該如何避免字典Values.Contains(),因爲它是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();
}
}
謝謝,這正是我一直在尋找的。 –