2

I'm using SignalR to notify clients about some changes. My hub (but it's not fundamental to know it's a SignalR hub) is defined as

public class NotificationHub : Hub { private static readonly IHubContext HubContext = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>(); private static readonly IDictionary<int, string> UserConnectionMapping = new Dictionary<int, string>(); private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private const string UserId = "UserId"; private readonly object userConnectionMappingLock = new object(); public static void Static_UpdateStatus(int userId, string message) { lock(userConnectionMappingLock ) //This causes troubles { if (UserConnectionMapping.ContainsKey(userId)) { var connectionId = UserConnectionMapping[userId]; HubContext.Clients.Client(connectionId).updateNotifications(message); } } } public override Task OnConnected() { if (Context.QueryString[UserId] == null) return base.OnConnected(); var userId = int.Parse(Context.QueryString[UserId]); Log.Debug($"User {userId} connected on SignalR with Connection Id {Context.ConnectionId}"); lock (userConnectionMappingLock) { UserConnectionMapping[userId] = Context.ConnectionId; } return base.OnConnected(); } 

Since it's static the method (and it can't be otherwise since I need to access from external classes), should I declare the lock static as well? Consider that there will be only 1 instance of NotifyHub. Thanks

3
  • 1
    You can't use a non-static member from a static method. The compiler will prevent you. Make it static. Commented Jun 13, 2018 at 8:35
  • That's not the correct way to do it, you should exctrat the ConnectionMapping outside the hub in a singleton expose Add and Remove methods to handle connected and disconnected users, and to access the bub oustide the hubpipeline, have a look here stackoverflow.com/questions/15128125/… which points to this link learn.microsoft.com/en-us/aspnet/signalr/overview/… if it's not clear let me know I can give you sample code. Commented Jun 13, 2018 at 8:59
  • @lyz thanks for your point... an example would be really appreciated, why it's not the correct way to do? I don't either like the facto to have a static Hubcontext here Commented Jun 13, 2018 at 9:05

1 Answer 1

1

The thing you're locking and the thing being protected should really have the same lifetime and scope; at the moment UserConnectionMapping is static, and userConnectionMappingLock is per-instance, which is a recipe for disaster.

Frankly, static dictionaries are always a little dangerous, but they can be used safely; options:

  1. make userConnectionMappingLock match the scope of the dictionary - add static to userConnectionMappingLock (or remove static from UserConnectionMapping, see 3)
  2. lose userConnectionMappingLock completely (just throw it away), and lock on the dictionary itself (UserConnectionMapping)
  3. make UserConnectionMapping not be static - so you have a dictionary per hub instance (assuming the lifetime of NotificationHub works for that)
  4. use ConcurrentDictrionary<int,string>

I'd probably lean towards the last one - you're less likely to shoot your foot off with it. Although I think a case could be made for applying 3 in addition to any of 1/2/4.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.