You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何借助IActionFilter实现.NET Core站点访问数据记录与后台展示?

.NET Core 使用IActionFilter实现访问数据统计的具体方案

1. 定义访问记录存储实体

首先定义用于存储统计数据的实体类,适配你的数据库存储:

public class VisitRecord
{
    public int Id { get; set; }
    /// <summary>
    /// 访客IP地址
    /// </summary>
    public string IpAddress { get; set; }
    /// <summary>
    /// 访问的页面/接口路径
    /// </summary>
    public string RequestPath { get; set; }
    /// <summary>
    /// 访问时间
    /// </summary>
    public DateTime VisitTime { get; set; } = DateTime.Now;
    /// <summary>
    /// 登录用户ID,未登录为null
    /// </summary>
    public string? UserId { get; set; }
    /// <summary>
    /// 客户端UA标识,可选存储
    /// </summary>
    public string? UserAgent { get; set; }
}

建好实体后在你的DbContext中添加对应的DbSet配置,完成数据库迁移。

2. 实现自定义统计Filter

推荐使用异步IActionFilter实现,避免阻塞请求线程:

public class VisitStatisticsFilter : IAsyncActionFilter
{
    private readonly YourDbContext _dbContext;

    // 依赖注入数据库上下文,也可替换为Redis、日志服务等其他存储介质
    public VisitStatisticsFilter(YourDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        // 执行Action前记录访问数据,不影响正常请求逻辑
        var visitRecord = new VisitRecord
        {
            // 取真实访客IP,反向代理场景需额外处理X-Forwarded-For请求头
            IpAddress = context.HttpContext.Connection.RemoteIpAddress?.ToString() ?? "未知IP",
            RequestPath = context.HttpContext.Request.Path.ToString(),
            UserId = context.HttpContext.User.FindFirstValue(System.Security.Claims.ClaimTypes.NameIdentifier),
            UserAgent = context.HttpContext.Request.Headers.UserAgent.ToString()
        };
        _dbContext.VisitRecords.Add(visitRecord);
        await _dbContext.SaveChangesAsync();

        // 执行原本的Action逻辑
        var resultContext = await next();

        // 如果需要记录请求是否成功、响应状态码等信息,可在next执行后补充逻辑
        // visitRecord.StatusCode = resultContext.HttpContext.Response.StatusCode;
        // await _dbContext.SaveChangesAsync();
    }
}

3. 注册Filter生效

有两种注册方式可选,根据你的需求选择:

  • 全局注册:所有Controller的Action都会触发统计逻辑
    首先在Program.cs中注册Filter为Scoped服务(匹配DbContext的生命周期):
    builder.Services.AddScoped<VisitStatisticsFilter>();
    
    然后在控制器注册配置中添加全局Filter:
    builder.Services.AddControllersWithViews(options =>
    {
        options.Filters.AddService<VisitStatisticsFilter>();
    });
    
  • 局部注册:仅给需要统计的Controller/Action添加统计逻辑
    先完成上面的Filter服务注册,然后在对应的Controller或Action上添加属性即可:
    [ServiceFilter(typeof(VisitStatisticsFilter))]
    public class HomeController : Controller
    {
        // Action逻辑
    }
    

4. 管理后台数据统计查询示例

直接基于存储的VisitRecords表即可查询你需要的各类指标:

  • 每日登录用户数查询示例:
    // 查询指定日期的登录用户数
    var targetDate = new DateTime(2024,5,20);
    var dailyLoginUserCount = await _dbContext.VisitRecords
        .Where(x => x.VisitTime.Date == targetDate.Date && x.UserId != null)
        .Select(x => x.UserId)
        .Distinct()
        .CountAsync();
    
  • 页面访问量统计示例:
    // 按访问量倒序取TOP10访问页面
    var pageVisitRank = await _dbContext.VisitRecords
        .GroupBy(x => x.RequestPath)
        .Select(g => new { Path = g.Key, VisitCount = g.Count() })
        .OrderByDescending(x => x.VisitCount)
        .Take(10)
        .ToListAsync();
    
  • 每日独立访客数查询示例:
    var dailyUv = await _dbContext.VisitRecords
        .Where(x => x.VisitTime.Date == targetDate.Date)
        .Select(x => x.IpAddress)
        .Distinct()
        .CountAsync();
    

注意事项

  • 高流量场景下不建议每次请求直接写数据库,可先将访问数据写入Redis等缓存,定时批量同步到数据库,降低数据库压力
  • 用Nginx、CDN等反向代理部署时,需要提前配置ForwardedHeaders中间件,才能正确获取到访客的真实IP,避免获取到代理服务器的IP
  • Filter中尽量不要写同步阻塞逻辑,全部使用异步方法避免降低站点吞吐量

内容的提问来源于stack exchange,提问作者Cnrgrsc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 06:54:01