С# asp.net MVC: Когда обновлять LastActivityDate?
Я использую ASP.NET MVC и создаю общедоступный веб-сайт. Мне нужно отслеживать пользователей, которые находятся в сети. Я вижу, что стандартный способ в asp.net сделать это - отслеживать LastActivityDate
. Мой вопрос в том, когда следует обновить это?
Если я обновляю его каждый раз, когда пользователи нажимают на него, я почувствую, что производительность снижается. Однако, если я этого не сделаю, люди, которые только будут путешествовать, будут указаны как офлайн.
Каков наилучший способ сделать это в asp.net MVC?
Ответы
Ответ 1
Просто разместите javascript-вызов ajax в нижней части главной страницы, чтобы отслеживать это.
Не беспокойтесь о производительности в это время. Если он будет реализован, и вы увидите, что это проблема, вернитесь к поиску лучшего решения. Что-то настолько простое не должно быть проблемой производительности.
Просто подумайте об этом, как о Google Analytics. Он находится внизу миллионов страниц, что практически не влияет на пользовательский опыт этих сайтов.
Ответ 2
Просто столкнулся с той же проблемой, вот мой ответ для пользователей 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);
}
}
Ответ 3
Я начал использовать SimpleMembershipProvider. Это так просто, что больше нет LastActivityDate
отслеживания. Поэтому мне пришлось сворачивать самостоятельно.
Я только что добавил столбец LastActivityDate
в таблице "Пользователи", и мне было хорошо...
Следуя @Jab tip и используя страницу _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]()
Ответ 4
Почему бы не реализовать обновление LastActivityDate в качестве асинхронного вызова? Таким образом вы можете запустить обновление и продолжить обработку.
Ответ 5
Как @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,
Чарльз
Ответ 6
Я помещаю его в специальную очередь, которая позволяет только одному из заданного ключа находиться в очереди (и в этом случае использовать userId как ключ). Затем у меня есть поток с низким приоритетом, который прокладывает себе путь через эту очередь, делая обновления базы данных. Таким образом, для пользователя не замедляется, а один пользователь, выполняющий 100 обновлений за одну секунду, не наносит никакого вреда. Если это когда-нибудь станет проблемой, я сделаю эти обновления пакетными обновлениями по базе данных, но на данный момент этот подход работает очень хорошо.
Если приложение потерпит крах, я потеряю несколько секунд последних данных активности, но это будет просто отлично. Конечно, я также каждый раз обновляю объект User в памяти, чтобы он отражался в пользовательском интерфейсе, даже если он еще не пробился к базе данных. Обычно это там, пока они не получили завершенную страницу.
Ответ 7
Если вы используете InProc SessionState, используйте SessionStateModule.End событие. Это происходит, когда состояние сеанса удаляется из основного хранилища кеша. Обычно это происходит после 20 минут бездействия, вы можете установить время в web.config.
Ответ 8
Хороший вопрос, подумал об этом и насколько точны эти механизмы, можно рассматривать производительность, пару идей:
1) Отслеживание последней даты входа в систему
2) Используйте LastLoginDate + ожидаемую длину сеанса, чтобы установить какой-то LastOnlineDate, который можно использовать для проверки, находится ли пользователь в сети.
Ответ 9
Я не думаю, что есть большой штраф в производительности, если вы прибегаете к текущему зарегистрированному пользователю по каждому запросу и обновляете поле LastActivityDate
каждый раз (если у вас есть вопросы и вызывают метод GetUser
для зарегистрированных пользователей - на пользователя один раз на http-запрос). Таким образом, вы также можете убедиться, что у вас всегда есть данные пользователя, такие как электронная почта, имя и т.д., Если он обновит эти данные.
Ответ 10
Я попробовал Charlino код в Global.asax, как этот
protected void Application_BeginRequest(object sender, EventArgs e)
{
if ((Response.ContentType == "text/html") && (Request.IsAuthenticated))
{
}
}
Однако я все время получал Request.IsAuthenticated
false.
Поэтому я переместил код в метод в моем 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
not Membership
, но я добавил класс AppUser
, наследующий от класса IdentityUser
, и в классе AppUser
я добавил LastActivityDate property
.
Это находится в WebForms Applicaction
не MVC
.