I would like to track the last time a user was active on our website.
One approach would be to write middleware that updates the database with every authenticated page request. However, I'm a little concerned about the overhead of such a technique.
I would prefer to just track the last time they logged in. And if they were kept logged in for 30 days, for example, it is accurate enough for our purposes to know they had logged in within that timeframe.
However, it appears that ASP.NET Core Identity might use a sliding window, where the 30-day counter is reset every time they access a page.
Is there any way to get a rough idea of the last time they were active on the site without having to update the database with every page request?
NOTE: With previous versions of ASP.NET, it appeared we had session events (start, etc.). Seems something like that would be ideal if it didn't require updating the database on every page request.
You could use the LastActivityTime
with middleware to update the user's last activity time only if a certain amount of time has passed since the last recorded activity. This will reduce the database load. you could use in-memory cache to store the last activity time.
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
services.AddControllersWithViews();
.........
.......
}
Middleware:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Threading.Tasks;
public class ActivityTrackingMiddleware
{
private readonly RequestDelegate _next;
public ActivityTrackingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context, UserManager<ApplicationUser> userManager, IMemoryCache cache)
{
var user = context.User;
if (user.Identity.IsAuthenticated)
{
var userId = userManager.GetUserId(user);
var cacheKey = $"LastActivityTime_{userId}";
var lastActivity = cache.Get<DateTime>(cacheKey);
if (lastActivity == default || DateTime.UtcNow - lastActivity > TimeSpan.FromHours(1))
{
var appUser = await userManager.FindByIdAsync(userId);
if (appUser != null)
{
appUser.LastActivityTime = DateTime.UtcNow;
await userManager.UpdateAsync(appUser);
cache.Set(cacheKey, appUser.LastActivityTime, TimeSpan.FromDays(1));
}
}
}
await _next(context);
}
}
Do not forgot to register middleware in Startup.cs file:
app.UseMiddleware<ActivityTrackingMiddleware>();