2013-06-12 98 views
0

我有組織登錄到一個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(); 
    } 
} 

回答

1

首先,SignalR是非常聰明的,沒有任何訂閱發送到組時不浪費資源,所以你應該只要沒有任何成員發送到組,因爲它是OK浪費了幾個週期那樣做是罰款。

如果您沒有太多的組織,您可以使用ConcurrentDictionary<int,int>全部您的組織ID作爲您的密鑰和連接成員的數量作爲您的值。在OnConnected和OnDisconnected中可以分別使用Interlocked.Increment和Interlocked.Decrement來跟蹤當前連接的成員。然後,在您的任務中,可以循環使用鍵並跳過任何具有零連接成員的組織。

如果您不介意調用key.ToString(CultureInfo.InvariantCulture)以獲取組名稱,則此新的ConcurrentDictionary可以替換_uniqueOrganizations。

+0

謝謝,這正是我一直在尋找的。 –