方案 1:使用中间件
中间件适用于所有请求,它可以在请求进入 Controller 之前执行统计操作。
1. 创建 VisitMiddleware
public class VisitMiddleware
{
private readonly RequestDelegate _next;
private readonly IServiceScopeFactory _scopeFactory;
private readonly TimeSpan _timeSpan = TimeSpan.FromHours(1);
public VisitMiddleware(RequestDelegate next, IServiceScopeFactory scopeFactory)
{
_next = next;
_scopeFactory = scopeFactory; // 用于创建独立的 `DbContext`
}
public async Task InvokeAsync(HttpContext context)
{
using (var scope = _scopeFactory.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
string ipAddress = context.Connection.RemoteIpAddress?.ToString() ?? "Unknown";
string pageUrl = context.Request.Path;
var oneHourAgo = DateTime.Now - _timeSpan;
var existingVisit = dbContext.PageVisits
.Where(v => v.IpAddress == ipAddress && v.PageUrl == pageUrl && v.VisitTime >= oneHourAgo)
.FirstOrDefault();
if (existingVisit == null)
{
dbContext.PageVisits.Add(new PageVisit
{
IpAddress = ipAddress,
PageUrl = pageUrl,
VisitTime = DateTime.Now
});
await dbContext.SaveChangesAsync();
}
}
await _next(context); // 继续执行后续请求
}
}
2. 注册中间件
在 Program.cs 添加:
app.UseMiddleware<VisitMiddleware>();
方案 2:使用 ActionFilter
ActionFilter 适用于 Controller 层,它比中间件更灵活,可以指定仅在某些 Controller 或 Action 上执行。
1. 创建 VisitActionFilter
using Microsoft.AspNetCore.Mvc.Filters;
public class VisitActionFilter : IActionFilter
{
private readonly IServiceScopeFactory _scopeFactory;
private readonly TimeSpan _timeSpan = TimeSpan.FromHours(1);
public VisitActionFilter(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public void OnActionExecuting(ActionExecutingContext context)
{
using (var scope = _scopeFactory.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
string ipAddress = context.HttpContext.Connection.RemoteIpAddress?.ToString() ?? "Unknown";
string pageUrl = context.HttpContext.Request.Path;
var oneHourAgo = DateTime.UtcNow - _timeSpan;
var existingVisit = dbContext.PageVisits
.Where(v => v.IpAddress == ipAddress && v.PageUrl == pageUrl && v.VisitTime >= oneHourAgo)
.FirstOrDefault();
if (existingVisit == null)
{
dbContext.PageVisits.Add(new PageVisit
{
IpAddress = ipAddress,
PageUrl = pageUrl,
VisitTime = DateTime.UtcNow
});
dbContext.SaveChanges();
}
}
}
public void OnActionExecuted(ActionExecutedContext context) { }
}
2. 注册 ActionFilter
在 Program.cs 中:
services.AddScoped<VisitActionFilter>();
然后,在 Controller 中使用:
[ServiceFilter(typeof(VisitActionFilter))]
public class MyController : ControllerBase
{
// 所有请求自动记录访问
}
选哪种方案?
-
中间件 (
Middleware) 适用于 所有请求,不会局限于某个Controller。 -
过滤器 (
ActionFilter) 适用于 特定的Controller或Action,如果你不想记录所有页面,可以选择这个方案。
浙公网安备 33010602011771号