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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 19:05:45