2

In my application, I would like to check whether or not a particular user is logged in or not so I can display a status saying that that user is either "online" or "offline" to another user. This question is not about authenticating a user, only about getting the authentication status of a user.

How would I go about achieving this?

6
  • I don't think there's a built-in field that can be used for this. I would recommend creating a custom boolean field in your database on the AspNetUsers table. Set it to true when they login and false when they logout. Commented Apr 11, 2016 at 17:24
  • @DrewKennedy would that work if someone doesn't physically sign out, but instead closes the tab or browser, or navigates to another website? Commented Apr 11, 2016 at 17:29
  • That was a limitation I had in mind when I suggested that. The answer is I highly doubt it. This may have to be something done with JavaScript, but I can't provide a firm answer. Commented Apr 11, 2016 at 17:37
  • @DrewKennedy Now that you mention JavaScript, I might have to do something along the lines of tracking if a user is "active" and working around that. Similar to websites which sign you out of 30mins of inactivity Commented Apr 11, 2016 at 17:42
  • I can't be sure, but I wouldn't be surprised if they use WebSockets (SignalR, for example). Commented Apr 11, 2016 at 17:45

2 Answers 2

3

I think an option is to use some real-time solutions. SignalR for example. When a user logs in , you connect it to the hub. OnConnected() action save its state.Then OnDisconnected() remove from "OnlineRepository".

Update with example Here is how I did this in a asp.Net Mvc 5 app.

  • A Model class that holds a single user like:

    
        public class SingleConnection 
        {
            public SingleConnection()
            {
                ConnectionId = new List();
            }
            public string Id { get; set; }
            public List ConnectionId { get; set; }
        }
    
  • A connection mapping class that helps in adding/removeing and getting a user from list

    
        public class ConnectionMapping
        {
            private readonly List _connections = new List();
            public int Count
            {
                get
                {
                    return _connections.Count;
                }
            }
            public void Add(string key, string connectionId)
            {
                lock (_connections)
                {
                    var sn = _connections.Where(x => x.Id == key).FirstOrDefault();
                    if (sn != null) // there is a connection with this key
                    {
                        _connections.Find(x => x.Id == key).ConnectionId.Add(connectionId);
                    }
                    else
                    {
                        _connections.Add(new SingleConnection { Id = key, ConnectionId = new List { connectionId } });
                    }
                }
            }
            public List GetConnections(string id)
            {
                var con = _connections.Find(x => x.Id == id);
                return con != null ?  con.ConnectionId : new List();
            }
            public List AllConnectionIds() 
            {
                List results = new List();
                 var allItems = _connections.Where(x => x.ConnectionId.Count > 0).ToList();
                 foreach (var item in allItems)
                 {
                     results.AddRange(item.ConnectionId);
                 }
                 return results;
            }
            public List AllKeys() 
            {
                return _connections.Select(x => x.Id).ToList();
            }
            public void Remove(string key, string connectionId)
            {
                lock (_connections)
                {
                    var item = _connections.Find(x => x.Id == key);
                    if (_connections.Find(x => x.Id == key) != null)
                    {
                        _connections.Find(x => x.Id == key).ConnectionId.Remove(connectionId);
                        if (_connections.Find(x => x.Id == key).ConnectionId.Count == 0)
                        {
                            _connections.Remove(item);
                        }
                    }
                }
            }
        }
    
    • In my Hub Class
    
    private void IsActive(string connection, bool connected) 
    {
        Clients.All.clientconnected(connection, connected);
    }
    public override Task OnConnected()
    {
        string name = Context.User.Identity.Name;
        _connections.Add(name, Context.ConnectionId);
        IsActive(name, true);
        return base.OnConnected();
    }
    public override Task OnDisconnected(bool stopCalled)
    {
        string name = Context.User.Identity.Name;
        _connections.Remove(name, Context.ConnectionId);
        IsActive(name, false);
        return base.OnDisconnected(stopCalled);
    }
    public override Task OnReconnected()
    {
        string name = Context.User.Identity.Name;
        if (!_connections.GetConnections(name).Contains(Context.ConnectionId))
        {
            _connections.Add(name, Context.ConnectionId);
        }
        IsActive(name, false);
        return base.OnReconnected();
    }
    
  • In _Layout.cshtml

    
    // reference scripts
    // add a callback or the OnConnected() Will not fire
    chat.client.clientconnected = function (id,active){
    /*
    this will be called everytime a user connect or disconnect to the hub
    */
    }
    $.connection.hub.start();
    

Now with this I get in realtime all users that are online.
Note: This is an InMemory solution. Other solutions are here

Hope this helps...

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

2 Comments

Thanks for the suggestion, as well as @DrewKennedy, I'll look in to it!
Ok then,I will add a simple solution now here so you know where to start.
0

I would create my own system to define what are your "active" users:

  • You can keep the track of your users with a dictionary stored in the System.Web.Caching.Cache class.
  • In your base controller (because it would be instantiate for any client request) insert the current user to your cached dictionary by calling the KeepTrackActiveUsers method.
  • Add the SetInactiveUser method to your logout method.

{

private Dictionary<int,DateTime> ActiveUsers
{
    get 
    { 
      if(Cache["ActiveUsers"] == null)
        Cache["ActiveUsers"] = new Dictionary<int,DateTime>();
      return Cache["ActiveUsers"];
    } 
    set { Cache["ActiveUsers"] = value; }
}

private void KeepTrackActiveUsers()
{
    ActiveUsers[CurrentUserId] = DateTime.Now;
}   

private const int expirationTime = 600;   
private IEnumerable<int> GetActiveUsers()
{       
    DateTime now = DateTime.Now;
    ActiveUsers = ActiveUsers
        .Where(x => now.Subtract(x.Value).TotalSeconds < expirationTime)
        .ToDictionary(x => x.Key, x => x.Value);
    return ActiveUsers.Keys;
}

private void SetInactiveUser()
{
    ActiveUsers.Remove(CurrentUserId);
}

//to be defined
private int CurrentUserId
{
    get { return default(int); }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.