I'm using SignalR in a c# MVC web application. I want to have a list of objects ( UserDetail ) of the current form authenticated users. this object should hold the UserId ( Pk from table ) and ConnectionId ( SignalR ).
Today I'm using a static list in the hub class :
public static List<UserDetail> ConcurrentUsers = new List<UserDetail>();
And handle remove from list and insert to list in each of the Hub events
public override Task OnDisconnected(bool stopCalled)
{
if (ConcurrentUsers != null && ConcurrentUsers.Any(x => x.ConnectionId.Equals(Context.ConnectionId)))
ConcurrentUsers.Remove(ConcurrentUsers.Find(x => x.ConnectionId.Equals(Context.ConnectionId)));
return base.OnDisconnected(stopCalled);
}
public override Task OnConnected()
{
IsUserAuthenticated();
return base.OnConnected();
}
public override Task OnReconnected()
{
IsUserAuthenticated();
return base.OnReconnected();
}
private void IsUserAuthenticated()
{
if (HttpContext.Current != null && HttpContext.Current.User != null && HttpContext.Current.User.Identity.IsAuthenticated)
{
var user = DalHelper.GetUserNoTracking(HttpContext.Current.User.Identity.Name);
if (user == null)
{
Clients.Caller.GoToLogin();
return null;
}
if (!ConcurrentUsers.Any(x => x.ConnectionId.Equals(Context.ConnectionId)))
{
UserDetail ud = new UserDetail {
ConnectionId = Context.ConnectionId,
UserId = user.UserId,
};
ConcurrentUsers.Add(ud);
}
}
return null;
}
When I want to update a user with his data, let's say a new message he received I then can go over the list and find all the connectionId's of that user and push the message to all the connected User clients.
private static void FlushMessageToClient(Guid UserId, string Message)
{
string[] cids = Hub.ConcurrentUsers.Where(x => x.UserId.Equals(UserId)).Select(x => x.ConnectionId).ToArray();
foreach (string cid in cids)
{
Hub.Clients.Client(cid).messageReceived(Message);
}
}
All is working good until the web site runs for an hour with in and out users ,It will start to receive errors :
System.NullReferenceException: Object reference not set to an instance of an object. at Infra.ChatHub.b__16(UserDetail x) at System.Linq.Enumerable.Any[TSource](IEnumerable
1 source, Func
2 predicate) at ChatHub.IsUserAuthenticated()
Is there a better way to program it ?