如何在Audit.Net中获取调用SaveChangesAsync()的方法名称
解决方案
方法一:精准过滤StackTrace获取业务方法名
直接在AuditEntityAction中处理StackTrace,过滤掉框架、库相关的栈帧,定位到业务代码的方法:
.AuditEntityAction<AuditLog>((evt, entry, auditEntity) => { auditEntity.AuditData = entry.ToJson(); auditEntity.AuditDate = DateTime.UtcNow; var stackTrace = new StackTrace(); // 过滤掉系统、EF Core、Audit.NET的命名空间,找到第一个业务代码的栈帧 var targetFrame = stackTrace.GetFrames() ?.FirstOrDefault(frame => { var methodNamespace = frame.GetMethod().DeclaringType?.Namespace; return !string.IsNullOrEmpty(methodNamespace) && !methodNamespace.StartsWith("System.") && !methodNamespace.StartsWith("Microsoft.EntityFrameworkCore.") && !methodNamespace.StartsWith("Audit."); }); auditEntity.CallingMethod = targetFrame?.GetMethod().Name ?? "Unknown"; })
注意:需要根据你的业务代码命名空间调整过滤逻辑,比如业务代码都在YourApp.Business下,可以把条件改为methodNamespace.StartsWith("YourApp.Business"),定位更精准。
方法二:用扩展方法包装SaveChangesAsync(推荐)
通过自定义扩展方法,利用[CallerMemberName]特性自动获取调用方法名,传递给Audit.NET:
1. 定义扩展方法
public static class DbContextAuditExtensions { public static async Task<int> SaveChangesAsyncWithAudit(this DbContext context, [CallerMemberName] string callingMethod = "") { // 将方法名存入Audit的自定义字段 Audit.Core.Configuration.AddCustomAction(ActionType.OnScopeCreated, scope => { scope.SetCustomField("CallingMethod", callingMethod); }); return await context.SaveChangesAsync(); } }
2. 业务方法中调用扩展方法
public async Task DoSomeWork() { // 执行业务逻辑.. await dbConn.SaveChangesAsyncWithAudit(); // 自动传入当前方法名"DoSomeWork" return updated; }
3. 在AuditEntityAction中获取方法名
.AuditEntityAction<AuditLog>((evt, entry, auditEntity) => { auditEntity.AuditData = entry.ToJson(); auditEntity.AuditDate = DateTime.UtcNow; auditEntity.CallingMethod = evt.CustomFields["CallingMethod"] as string ?? "Unknown"; })
这种方法不受编译优化影响,结果更可靠,唯一需要修改业务代码的调用方式。
方法三:AsyncLocal结合AOP传递上下文
如果不想修改业务代码,可通过AsyncLocal存储当前方法名,配合AOP自动注入上下文:
1. 定义上下文存储类
public static class AuditMethodContext { private static readonly AsyncLocal<string> _currentMethod = new AsyncLocal<string>(); public static string CurrentMethod { get => _currentMethod.Value; set => _currentMethod.Value = value; } }
2. 用AOP拦截业务方法(以AspectCore为例)
public class AuditMethodInterceptor : AbstractInterceptorAttribute { public override async Task Invoke(AspectContext context, AspectDelegate next) { AuditMethodContext.CurrentMethod = context.ImplementationMethod.Name; try { await next(context); } finally { AuditMethodContext.CurrentMethod = null; } } }
3. 业务方法添加拦截器特性
[AuditMethodInterceptor] public async Task DoSomeWork() { // 执行业务逻辑.. await dbConn.SaveChangesAsync(); return updated; }
4. 在AuditEntityAction中获取方法名
.AuditEntityAction<AuditLog>((evt, entry, auditEntity) => { auditEntity.AuditData = entry.ToJson(); auditEntity.AuditDate = DateTime.UtcNow; auditEntity.CallingMethod = AuditMethodContext.CurrentMethod ?? "Unknown"; })
这种方式无需修改业务代码的调用逻辑,但需要引入AOP框架,适合大规模项目统一配置。
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

