简体   繁体   中英

C# asp.net MVC: When to update LastActivityDate?

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 around will be listed as offline.

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

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.

Just ran into the same problem, here's my answer for MVC users:

The idea is to trigger Membership.GetUser("..", true) for every page load. This will automatically update the LastActivityDate.

I put this in my global.asax under "RegisterGlobalFilters":

filters.Add(new MembershipTriggerLastActivityDate());

I created a new class that looks like this:

class MembershipTriggerLastActivityDate : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            MembershipUser user = Membership.GetUser(filterContext.HttpContext.User.Identity.Name, true);
        }   
        base.OnActionExecuting(filterContext);
    }
}

I started using the SimpleMembershipProvider . It's so simple that there's no more LastActivityDate tracking. So I had to roll my own.

I just added a LastActivityDate column in the Users table and was good to go...

Following @Jab's tip and using the _Layout.cshtml page (master page) in an ASP.NET MVC app, I did this with the help of jQuery:

$(document).ready((function () {

    var isUserAuthenticated = '@User.Identity.IsAuthenticated';

    if (isUserAuthenticated) {

        $.ajax({
            type: "POST",
            url: "@Url.Action(MVC.Account.ActionNames.UpdateLastActivityDate, MVC.Account.Name)",
            data: { userName: '@User.Identity.Name' },
            cache: false
        });
    }
});

Here's the action method:

public virtual ActionResult UpdateLastActivityDate(string userName)
{
    User user = Database.Users.Single(u => u.UserName == userName);

    user.LastActivityDate = DateTime.Now;

    Database.Entry(user).State = EntityState.Modified;

    Database.SaveChanges();

    return new EmptyResult();
}

Only 133ms (YMMV) :-)

在此输入图像描述

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

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

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.

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.

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.

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.

I tried Charlino 's code in the Global.asax like this

        protected void Application_BeginRequest(object sender, EventArgs e)
    {
        if ((Response.ContentType == "text/html") && (Request.IsAuthenticated))
        {

        }
    }

However I was getting the Request.IsAuthenticated false all the time. So I moved the code to a method in my Site.Master page like this

 public void RegisterActivity()
    {
        if ((Response.ContentType == "text/html") && (Request.IsAuthenticated))
        {
            string userName = Page.User.Identity.Name;

            UserManager userManager = new UserManager();
            AppUser appUser = userManager.FindByName(userName);
            appUser.LastActivityDate = DateTime.UtcNow;
            userManager.Update(appUser);
        }
    }

I call the method from the Master page Page_Load event, and there it worked.

I'm using asp.net Identity not Membership but I added an AppUser class inheriting from the IdentityUser class and in the AppUser class I added LastActivityDate property .

This is in a WebForms Applicaction not MVC .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM