views:

246

answers:

7

I'm using asp.net mvc and creating a public website. I need to keep track of users that are online. I see that the standard way in asp.net of doing this is to keep track of LastActivityDate. My question is when should I update this?

If I update it every time the users clicks somewhere, I will feel a performance draw back. However if I do not do that, people that only surf arround will be listed as offline.

What is the best way to do this in asp.net MVC?

A: 

Good question, have thought about that too and how accurate these mechanisms can be considering performance, a couple of ideas:

1) Track the the last login date

2) Use the LastLoginDate + the expected session length to set some kind of LastOnlineDate that can be used to check if the user is online.

Mark Redman
But what happens if a user signs in and then surfs arround for 3 hours and the session length is 20 mins? Then the user will be listed as offline incorrectly. Which would happen in most cases?
Oskar Kjellin
You could store this LastOnlineDate in session and set some flag to update this based on a user action (page load)
Mark Redman
...when the current date is greater than the LastOnlineDate ...
Mark Redman
+1  A: 

Why not implement the update to LastActivityDate as an asynchronous call? That way you can fire the update and continue processing.

Steve Horn
Is there any event in the global.asax that will catch these async perhaps?
Oskar Kjellin
Application_BeginRequest gets called in the global.asax. You could theoretically use that entry point to log the date for the user.
Steve Horn
+1  A: 

If you are using InProc SessionState, use the SessionStateModule.End event. This happens when the session state is evicted from the underlying cache storage. Typically this happens after 20 minutes of inactivity, you can set the time in web.config.

driis
Testing this now :)
Oskar Kjellin
This event does not seem to fire properly for me.
Oskar Kjellin
A: 

I don't think there is big penalty in performance if you fetch the current logged-in user on every request and update the LastActivityDate field every time (if you have care and invoke the GetUser method for the logged-in user once per http-request). In this way you can also make sure you always have the user's data fresh, like email, name, etc in case he/she updates that data.

uvita
Would holding this LastActivityDate in a separate table that only includes the UserID|LastActivityDate reduce some overhead?
Mark Redman
@Mark - that would surely just add an unnecessary JOIN
Hightechrider
+1  A: 

Just put an ajax javascript call at the bottom of your master page to track this.

Don't worry about performance at this time. If it's implemented and you see it being a problem then come back to finding a better solution. Something so simple shouldn't be a performance problem.

Just think about it like Google analytics. It sits at the bottom of millions of pages with little to no impact on the user experiences of those sites.

Jab
Great tip. Ended up doing this :)
Oskar Kjellin
+1  A: 

As @Jab says, just implement it and if you see it as a performance issue in the future - deal with it then.

This is how I've done it in my application:

protected void Application_EndRequest()
{
    if ((Response.ContentType == "text/html") && (Request.IsAuthenticated))
    {
        var webUser = Context.User as WebUser;
        if (webUser != null)
        {
            //Update their last activity
            webUser.LastActivity = DateTime.UtcNow;

            //Update their page hit counter
            webUser.ActivityCounter += 1;

            //Save them
            var webUserRepo = Kernel.Get<IWebUserRepository>(); //Ninject
            webUserRepo.Update(webUser);
        }
    }
}

I haven't had any problems with performance.

HTHs,
Charles

Charlino
+1  A: 

I put it into a special queue that allows only one of a given key to be in the queue (and use the userId as the key in this case). Then I have a low priority thread that works its way through this queue doing database updates. Thus no slow down for the user, and one user doing 100 updates in one second doesn't cause any harm. If it ever becomes an issue I'll make those updates into batch updates against the database but for now this approach works just fine.

If the application crashed I'd lose a few seconds of last activity data but that's just fine. Of course I also update the in memory User object every time so that it's reflected in the UI even if it hasn't made its way to the database yet. Typically it's there before they've received the completed page anyway.

Hightechrider