Toolhub / Services /BaseToolService.cs
unifare
Initial commit: ToolHub ASP.NET Core app
5fc700d
using ToolHub.Models;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;
namespace ToolHub.Services;
/// <summary>
/// 工具基类服务,提供统计数据和用户访问记录功能
/// </summary>
public abstract class BaseToolService
{
protected readonly IFreeSql _freeSql;
protected readonly IHttpContextAccessor _httpContextAccessor;
protected BaseToolService(IFreeSql freeSql, IHttpContextAccessor httpContextAccessor)
{
_freeSql = freeSql;
_httpContextAccessor = httpContextAccessor;
}
/// <summary>
/// 记录工具访问
/// </summary>
protected async Task RecordToolAccessAsync(int toolId, string accessType = "view", int duration = 0)
{
try
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext == null) return;
var userId = GetCurrentUserId();
var sessionId = GetSessionId();
var ipAddress = GetClientIpAddress();
var userAgent = GetUserAgent();
var referer = GetReferer();
var access = new UserToolAccess
{
UserId = userId,
ToolId = toolId,
SessionId = sessionId,
IpAddress = ipAddress,
UserAgent = userAgent,
Referer = referer,
AccessType = accessType,
Duration = duration
};
await _freeSql.Insert(access).ExecuteAffrowsAsync();
// 更新工具总访问量
await _freeSql.Update<Tool>()
.Where(t => t.Id == toolId)
.Set(t => t.ViewCount + 1)
.ExecuteAffrowsAsync();
// 更新日统计数据
await UpdateDailyStatisticsAsync(toolId, accessType);
}
catch (Exception ex)
{
// 记录错误但不影响主流程
Console.WriteLine($"记录工具访问失败: {ex.Message}");
}
}
/// <summary>
/// 更新日统计数据
/// </summary>
protected async Task UpdateDailyStatisticsAsync(int toolId, string accessType)
{
var today = DateTime.Today;
var stats = await _freeSql.Select<ToolStatistics>()
.Where(s => s.ToolId == toolId && s.Date == today)
.FirstAsync();
if (stats == null)
{
// 创建新的日统计记录
stats = new ToolStatistics
{
ToolId = toolId,
Date = today
};
await _freeSql.Insert(stats).ExecuteAffrowsAsync();
}
// 更新统计数据
var updateQuery = _freeSql.Update<ToolStatistics>()
.Where(s => s.Id == stats.Id);
switch (accessType.ToLower())
{
case "view":
updateQuery.Set(s => s.DailyViews + 1);
break;
case "favorite":
updateQuery.Set(s => s.DailyFavorites + 1);
break;
case "share":
updateQuery.Set(s => s.DailyShares + 1);
break;
case "download":
updateQuery.Set(s => s.DailyDownloads + 1);
break;
}
updateQuery.Set(s => s.UpdatedAt, DateTime.Now);
await updateQuery.ExecuteAffrowsAsync();
}
/// <summary>
/// 获取工具统计数据
/// </summary>
protected async Task<ToolStatistics?> GetToolStatisticsAsync(int toolId, DateTime date)
{
return await _freeSql.Select<ToolStatistics>()
.Where(s => s.ToolId == toolId && s.Date == date)
.FirstAsync();
}
/// <summary>
/// 获取工具访问记录
/// </summary>
protected async Task<List<UserToolAccess>> GetToolAccessRecordsAsync(int toolId, DateTime? startDate = null, DateTime? endDate = null, int limit = 100)
{
var query = _freeSql.Select<UserToolAccess>()
.Include(ua => ua.User)
.Where(ua => ua.ToolId == toolId);
if (startDate.HasValue)
query = query.Where(ua => ua.CreatedAt >= startDate.Value);
if (endDate.HasValue)
query = query.Where(ua => ua.CreatedAt <= endDate.Value.AddDays(1));
return await query
.OrderByDescending(ua => ua.CreatedAt)
.Take(limit)
.ToListAsync();
}
/// <summary>
/// 获取用户访问的工具记录
/// </summary>
protected async Task<List<UserToolAccess>> GetUserToolAccessRecordsAsync(int userId, DateTime? startDate = null, DateTime? endDate = null, int limit = 100)
{
var query = _freeSql.Select<UserToolAccess>()
.Include(ua => ua.Tool)
.Where(ua => ua.UserId == userId);
if (startDate.HasValue)
query = query.Where(ua => ua.CreatedAt >= startDate.Value);
if (endDate.HasValue)
query = query.Where(ua => ua.CreatedAt <= endDate.Value);
return await query
.OrderByDescending(ua => ua.CreatedAt)
.Take(limit)
.ToListAsync();
}
/// <summary>
/// 获取热门工具(基于访问量)
/// </summary>
protected async Task<List<Tool>> GetPopularToolsAsync(int count = 10, DateTime? startDate = null)
{
var query = _freeSql.Select<Tool>()
.Include(t => t.Category)
.Where(t => t.IsActive);
if (startDate.HasValue)
{
// 基于指定日期后的访问量排序
var toolAccessData = _freeSql.Select<UserToolAccess>()
.Where(ua => ua.CreatedAt >= startDate.Value)
.GroupBy(ua => ua.ToolId)
.Select(g => new { ToolId = g.Key, Count = g.Count() })
.OrderByDescending(x => x.Count)
.Take(count)
.ToList();
var toolIds = toolAccessData.Select(x => x.ToolId).ToList();
if (toolIds.Any())
{
query = query.Where(t => toolIds.Contains(t.Id));
}
}
else
{
// 基于总访问量排序
query = query.OrderByDescending(t => t.ViewCount);
}
return await query.Take(count).ToListAsync();
}
/// <summary>
/// 获取当前用户ID
/// </summary>
protected int? GetCurrentUserId()
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext?.User?.Identity?.IsAuthenticated == true)
{
var userIdClaim = httpContext.User.FindFirst(ClaimTypes.NameIdentifier);
if (userIdClaim != null && int.TryParse(userIdClaim.Value, out int userId))
{
return userId;
}
}
return null;
}
/// <summary>
/// 获取会话ID
/// </summary>
protected string? GetSessionId()
{
string sessionId = string.Empty;
try
{
var httpContext = _httpContextAccessor.HttpContext;
return httpContext?.Session?.Id;
}
catch (Exception ex)
{
Console.WriteLine($"获取会话ID失败: {ex.Message}");
return sessionId;
}
}
/// <summary>
/// 获取客户端IP地址
/// </summary>
protected string? GetClientIpAddress()
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext == null) return null;
// 尝试从各种头部获取真实IP
var ip = httpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault() ??
httpContext.Request.Headers["X-Real-IP"].FirstOrDefault() ??
httpContext.Connection.RemoteIpAddress?.ToString();
return ip;
}
/// <summary>
/// 获取用户代理
/// </summary>
protected string? GetUserAgent()
{
var httpContext = _httpContextAccessor.HttpContext;
return httpContext?.Request.Headers["User-Agent"].FirstOrDefault();
}
/// <summary>
/// 获取来源页面
/// </summary>
protected string? GetReferer()
{
var httpContext = _httpContextAccessor.HttpContext;
return httpContext?.Request.Headers["Referer"].FirstOrDefault();
}
/// <summary>
/// 计算平均停留时间
/// </summary>
protected async Task UpdateAverageDurationAsync(int toolId)
{
var today = DateTime.Today;
var avgDuration = await _freeSql.Select<UserToolAccess>()
.Where(ua => ua.ToolId == toolId && ua.CreatedAt >= today && ua.Duration > 0)
.AvgAsync(ua => ua.Duration);
if (avgDuration > 0)
{
await _freeSql.Update<ToolStatistics>()
.Where(s => s.ToolId == toolId && s.Date == today)
.Set(s => s.AverageDuration, (decimal)avgDuration)
.ExecuteAffrowsAsync();
}
}
/// <summary>
/// 获取工具使用趋势数据
/// </summary>
protected async Task<List<object>> GetToolUsageTrendAsync(int toolId, int days = 30)
{
var endDate = DateTime.Today;
var startDate = endDate.AddDays(-days + 1);
var stats = await _freeSql.Select<ToolStatistics>()
.Where(s => s.ToolId == toolId && s.Date >= startDate && s.Date <= endDate)
.OrderBy(s => s.Date)
.ToListAsync();
var result = new List<object>();
for (var date = startDate; date <= endDate; date = date.AddDays(1))
{
var dayStats = stats.FirstOrDefault(s => s.Date == date);
result.Add(new
{
Date = date.ToString("yyyy-MM-dd"),
Views = dayStats?.DailyViews ?? 0,
UniqueViews = dayStats?.DailyUniqueViews ?? 0,
Favorites = dayStats?.DailyFavorites ?? 0,
Shares = dayStats?.DailyShares ?? 0,
Downloads = dayStats?.DailyDownloads ?? 0,
AverageDuration = dayStats?.AverageDuration ?? 0
});
}
return result;
}
}