diff --git a/EJ2CoreSampleBrowser_NET10.csproj b/EJ2CoreSampleBrowser_NET10.csproj
index 9bb178cd..b5ecd70e 100644
--- a/EJ2CoreSampleBrowser_NET10.csproj
+++ b/EJ2CoreSampleBrowser_NET10.csproj
@@ -47,6 +47,7 @@
+
diff --git a/EJ2CoreSampleBrowser_NET8.csproj b/EJ2CoreSampleBrowser_NET8.csproj
index e7fa87bf..3b0c19f9 100644
--- a/EJ2CoreSampleBrowser_NET8.csproj
+++ b/EJ2CoreSampleBrowser_NET8.csproj
@@ -47,6 +47,7 @@
+
diff --git a/EJ2CoreSampleBrowser_NET9.csproj b/EJ2CoreSampleBrowser_NET9.csproj
index 08779feb..26720efa 100644
--- a/EJ2CoreSampleBrowser_NET9.csproj
+++ b/EJ2CoreSampleBrowser_NET9.csproj
@@ -47,6 +47,7 @@
+
diff --git a/Pages/DiagramHub.cs b/Pages/DiagramHub.cs
index 68c72b48..7932da1c 100644
--- a/Pages/DiagramHub.cs
+++ b/Pages/DiagramHub.cs
@@ -10,6 +10,7 @@
using EJ2CoreSampleBrowser.Models;
using System.Collections.Concurrent;
using Newtonsoft.Json;
+using AsyncKeyedLock;
namespace EJ2SDiagramSample.Pages
{
@@ -117,64 +118,52 @@ public async Task SendCurrentSelectionsToCaller()
}
#endregion
- private static readonly ConcurrentDictionary _connLocks = new();
+ private static readonly AsyncKeyedLocker _connLocks = new();
- private static SemaphoreSlim GetConnectionLock(string connectionId)
- {
- return _connLocks.GetOrAdd(connectionId, _ => new SemaphoreSlim(1, 1));
- }
public async Task BroadcastToOtherClients(List payloads, long clientVersion, List? elementIds, SelectionEvent currentSelection, string roomName)
{
var connId = Context.ConnectionId;
- var gate = GetConnectionLock(connId);
- await gate.WaitAsync();
- try
- {
- var versionKey = "diagram:version";
+ using var _ = await _connLocks.LockAsync(connId);
+ var versionKey = "diagram:version";
- var (acceptedSingle, serverVersionSingle) = await _redisService.CompareAndIncrementAsync(versionKey, clientVersion);
- long serverVersionFinal = serverVersionSingle;
+ var (acceptedSingle, serverVersionSingle) = await _redisService.CompareAndIncrementAsync(versionKey, clientVersion);
+ long serverVersionFinal = serverVersionSingle;
- if (!acceptedSingle)
+ if (!acceptedSingle)
+ {
+ var recentUpdates = await GetUpdatesSinceVersionAsync(clientVersion, maxScan: 200);
+ var recentlyTouched = new HashSet(StringComparer.Ordinal);
+ foreach (var upd in recentUpdates)
{
- var recentUpdates = await GetUpdatesSinceVersionAsync(clientVersion, maxScan: 200);
- var recentlyTouched = new HashSet(StringComparer.Ordinal);
- foreach (var upd in recentUpdates)
- {
- if (upd.ModifiedElementIds == null) continue;
- foreach (var id in upd.ModifiedElementIds)
- recentlyTouched.Add(id);
- }
-
- var overlaps = elementIds?.Where(id => recentlyTouched.Contains(id)).Distinct().ToList();
- if (overlaps?.Count > 0)
- {
- await Clients.Caller.SendAsync("RevertCurrentChanges", elementIds);
- await Clients.Caller.SendAsync("ShowConflict");
- return;
- }
-
- var (_, newServerVersion) = await _redisService.CompareAndIncrementAsync(versionKey, serverVersionSingle);
- serverVersionFinal = newServerVersion;
+ if (upd.ModifiedElementIds == null) continue;
+ foreach (var id in upd.ModifiedElementIds)
+ recentlyTouched.Add(id);
}
- var update = new DiagramUpdateMessage
+ var overlaps = elementIds?.Where(id => recentlyTouched.Contains(id)).Distinct().ToList();
+ if (overlaps?.Count > 0)
{
- SourceConnectionId = connId,
- Version = serverVersionFinal,
- ModifiedElementIds = elementIds
- };
+ await Clients.Caller.SendAsync("RevertCurrentChanges", elementIds);
+ await Clients.Caller.SendAsync("ShowConflict");
+ return;
+ }
- await StoreUpdateInRedis(update, connId);
- SelectionEvent selectionEvent = BuildSelectedElementEvent(currentSelection.ElementIds, currentSelection.SelectorBounds);
- await UpdateSelectionBoundsInRedis(selectionEvent, currentSelection.ElementIds, currentSelection.SelectorBounds);
- await Clients.OthersInGroup(roomName).SendAsync("ReceiveData", payloads, serverVersionFinal, selectionEvent);
- await RemoveOldUpdates(serverVersionFinal);
+ var (_, newServerVersion) = await _redisService.CompareAndIncrementAsync(versionKey, serverVersionSingle);
+ serverVersionFinal = newServerVersion;
}
- finally
+
+ var update = new DiagramUpdateMessage
{
- gate.Release();
- }
+ SourceConnectionId = connId,
+ Version = serverVersionFinal,
+ ModifiedElementIds = elementIds
+ };
+
+ await StoreUpdateInRedis(update, connId);
+ SelectionEvent selectionEvent = BuildSelectedElementEvent(currentSelection.ElementIds, currentSelection.SelectorBounds);
+ await UpdateSelectionBoundsInRedis(selectionEvent, currentSelection.ElementIds, currentSelection.SelectorBounds);
+ await Clients.OthersInGroup(roomName).SendAsync("ReceiveData", payloads, serverVersionFinal, selectionEvent);
+ await RemoveOldUpdates(serverVersionFinal);
}
private async Task RemoveOldUpdates(long currentServerVersion)
{
@@ -379,7 +368,7 @@ public async Task JoinDiagram(string roomName, string diagramId, string userName
_diagramUsers.AddOrUpdate(userId, diagramUser,
(key, existingValue) => diagramUser
);
- await RequestAndLoadStateAsync(roomName,diagramId,Context.ConnectionId,Context.ConnectionAborted);
+ await RequestAndLoadStateAsync(roomName, diagramId, Context.ConnectionId, Context.ConnectionAborted);
long currentServerVersion = await GetDiagramVersion();
await Clients.Caller.SendAsync("UpdateVersion", currentServerVersion);