.netcore 实现操作日志记录
- 最近开发中接到一个需求,需要记录用户每次操作的步骤。注意,不是错误日志。
- 本人用的是.net6.0, 但大致思路是一样的。🚀
- 首先建立实体(英语不是很标准,百度查的,各位亲喷哈 各种反弹。)
public partial class LogOperation
{
public int Id { get; set; }
public int? Operation { get; set; }
public string? Desc { get; set; }
public string? Creator { get; set; }
public DateTime? CreateTime { get; set; }
public string? Browser { get; set; }
public string? Account { get; set; }
public string? Category { get; set; }
public string? SubCategory { get; set; }
public decimal? Cost { get; set; }
public string? Path { get; set; }
public string? Ip { get; set; }
public string? Method { get; set; }
public string? Param { get; set; }
public string? Result { get; set; }
public string? System { get; set; }
}
- 有了刚才建立的实体之后就好办了,准备写一个特性加全局过滤器,只要加到方法上,全局拦截一下。只要找到标记的就记录一次。我这里是讲需要记录的内容通过特性传入的,当然你也可以根据你自己的需求去写。
- 使用异步actionFilter 只需要实现 他的 :OnActionExecutionAsync 方法 (注意这里的异步不是拦截异步是指的是 当前OnActionExecutionAsync方法内执行的内容是异步的)
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
public class OperationLogAttribute : Attribute
{
public string Category { get; set; }
public string SubCategory { get; set; }
public string Desc { get; set; }
public OperationTypeEnum Operation { get; set; }
public OperationLogAttribute(string category, string subCategory, string desc, OperationTypeEnum operation)
{
Category = category;
SubCategory = subCategory;
Desc = desc;
Operation = operation;
}
}
public class OperationLogFilter : IAsyncActionFilter
{
private Account Account;
private readonly IHttpContextService _http;
private readonly IRepository<LogOperation> _operationRep;
private readonly IHttpContextAccessor _httpContextAccessor;
public OperationLogFilter(IRepository<LogOperation> operationRep, IHttpContextService http, IHttpContextAccessor httpContextAccessor)
{
_operationRep = operationRep;
_http = http;
_httpContextAccessor = httpContextAccessor;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
var method = actionDescriptor?.MethodInfo;
if (method != null && !method.IsDefined(typeof(OperationLogAttribute), true))
{
_ = await next();
#region 如果需要获取执行结果,可以通过以下方式
#endregion
}
else
{
Account = await _http.Get_Current_User();
var ip = _httpContextAccessor?.HttpContext?.GetIPV4();
var userAgent = _httpContextAccessor?.HttpContext?.Request.Headers["User-Agent"];
var (osFamily, uaFamily) = userAgent.GetBrowerAndSystem();
var sw = new Stopwatch();
sw.Start();
_ = await next();
sw.Stop();
foreach (var attributes in method.GetCustomAttributes(true))
{
try
{
OperationLogAttribute? operationLog = attributes as OperationLogAttribute;
if (operationLog != null)
{
await _operationRep.InsertAsync(new LogOperation
{
Creator = Account.UserName ??= "未知",
Account = Account.AccountName ??= "未知",
Browser = uaFamily,
System = osFamily,
Category = operationLog.Category,
SubCategory = operationLog.SubCategory,
Desc = operationLog.Desc,
Operation = Convert.ToInt32(operationLog.Operation),
Path = context.HttpContext.Request.Path.Value,
Ip = ip,
Cost = sw.ElapsedMilliseconds,
Method = actionDescriptor?.ActionName,
CreateTime = DateTime.Now,
Param = context.ActionArguments.Count > 0 ? JsonConvert.SerializeObject(context.ActionArguments) : "",
});
}
}
catch (Exception)
{
_ = await next();
}
}
}
}
}
- 过滤器也写完了,那么接下来就是关键的注册了,不注册相当于白写了嘛🤭找到,启动类Program, 添加如下代码
- 该写的都写了,那么现在就差怎么使用了。还记得刚开始说的是特性吗,那么标记在方法上就行了。