C # asp.net MVC: когда обновлять LastActivityDate? - PullRequest
12 голосов
/ 25 апреля 2010

Я использую ASP.NET MVC и создаю общедоступный веб-сайт. Мне нужно отслеживать пользователей, которые в сети. Я вижу, что стандартным способом asp.net это отслеживать LastActivityDate. Мой вопрос, когда я должен обновить это?

Если я буду обновлять его каждый раз, когда пользователи щелкают где-то, я почувствую снижение производительности Однако, если я не сделаю этого, люди, которые только путешествуют вокруг, будут перечислены как офлайн.

Каков наилучший способ сделать это в asp.net MVC?

Ответы [ 10 ]

6 голосов
/ 18 ноября 2011

Просто столкнулся с той же проблемой, вот мой ответ для пользователей MVC:

Идея состоит в том, чтобы запускать Membership.GetUser ("..", true) для каждой загрузки страницы. Это автоматически обновит LastActivityDate.

Я поместил это в свой global.asax под "RegisterGlobalFilters":

filters.Add(new MembershipTriggerLastActivityDate());

Я создал новый класс, который выглядит следующим образом:

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);
    }
}
6 голосов
/ 26 апреля 2010

Просто поместите вызов ajax javascript внизу главной страницы, чтобы отслеживать это.

Не беспокойтесь о производительности в данный момент. Если он реализован, и вы видите, что это проблема, вернитесь к поиску лучшего решения. Что-то такое простое не должно быть проблемой производительности.

Просто подумайте об этом, как о Google Analytics. Он находится на дне миллионов страниц, практически не влияя на пользовательский интерфейс этих сайтов.

4 голосов
/ 04 октября 2012

Я начал использовать SimpleMembershipProvider . Это так просто, что больше нет отслеживания LastActivityDate. Так что мне пришлось катиться самостоятельно.

Я только что добавил столбец LastActivityDate в таблицу Users, и все было хорошо ...

Следуя подсказке @ Jab и используя страницу _Layout.cshtml (главную страницу) в приложении ASP.NET MVC, я сделал это с помощью 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
        });
    }
});

Вот метод действия:

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();
}

Только 133 мс (YMMV): -)

enter image description here

2 голосов
/ 26 апреля 2010

Я помещаю его в специальную очередь, которая позволяет только одному из заданных ключей находиться в очереди (и в этом случае в качестве ключа используется userId) Затем у меня есть поток с низким приоритетом, который проходит через эту очередь и выполняет обновления базы данных. Таким образом, нет замедления для пользователя, и один пользователь, делающий 100 обновлений в секунду, не причинит никакого вреда. Если это когда-нибудь станет проблемой, я превращу эти обновления в пакетные обновления для базы данных, но сейчас этот подход работает просто отлично.

В случае сбоя приложения я потерял бы несколько секунд данных о последних действиях, но это нормально. Конечно, я также обновляю объект User в памяти каждый раз, чтобы он отражался в пользовательском интерфейсе, даже если он еще не попал в базу данных. Как правило, он там до того, как они получили заполненную страницу.

2 голосов
/ 26 апреля 2010

Как говорит @Jab, просто внедрите его, и если в будущем вы увидите, что это проблема с производительностью, тогда разберитесь с этим.

Вот как я это сделал в своем приложении:

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);
        }
    }
}

У меня не было проблем с производительностью.

HTHS
Charles

2 голосов
/ 26 апреля 2010

Почему бы не реализовать обновление до LastActivityDate как асинхронный вызов? Таким образом, вы можете запустить обновление и продолжить обработку.

1 голос
/ 26 апреля 2010

Если вы используете InProc SessionState, используйте событие SessionStateModule.End . Это происходит, когда состояние сеанса высвобождается из основного хранилища кэша. Обычно это происходит после 20 минут бездействия, вы можете установить время в web.config.

0 голосов
/ 30 января 2017

Я попробовал код Чарлино в Global.asax, как это

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

        }
    }

Однако я все время получал Request.IsAuthenticated ложь. Поэтому я переместил код в метод в моем Site.Master page, как это

 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);
        }
    }

Я вызываю метод из события Master page Page_Load, и там он работает.

Я использую asp.net Identity, а не Membership, но я добавил класс AppUser, унаследованный от класса IdentityUser, а в классе AppUser я добавил LastActivityDate property.

Это в WebForms Applicaction не MVC.

0 голосов
/ 26 апреля 2010

Я не думаю, что это приведет к значительному снижению производительности, если вы будете извлекать текущего вошедшего в систему пользователя при каждом запросе и обновлять поле LastActivityDate каждый раз (если вы заботитесь и вызываете метод GetUser для зарегистрированного - у пользователя один раз за http-запрос). Таким образом, вы также можете быть уверены, что у вас всегда будут свежие данные пользователя, такие как электронная почта, имя и т. Д. На случай, если он обновит эти данные.

0 голосов
/ 25 апреля 2010

Хороший вопрос, тоже подумал об этом и о том, насколько точными могут быть эти механизмы с точки зрения производительности, пара идей:

1) Отслеживание последней даты входа в систему

2) Используйте LastLoginDate + ожидаемую длительность сеанса, чтобы установить какой-то тип LastOnlineDate, который можно использовать для проверки, если пользователь находится в сети.

...