1

I have the following Setup

Audit.Core.Configuration.Setup() // Triggered on a database save.
    .UseEntityFramework(ef => ef
        .AuditTypeExplicitMapper(m => m
            .Map<Item, AuditLog>()
            .AuditEntityAction<AuditLog>((evt, entry, auditEntity) =>
            {
                auditEntity.AuditData = entry.ToJson();
                auditEntity.AuditDate = DateTime.UtcNow;
                auditEntity.CallingMethod = "Calling Method"; <-- Where I need the calling method.
            })
        )
    );
    public async Task DoSomeWork() {  //<--- I want to get "DoSomeWork"
        // Some work..
        await dbConn.SaveChangesAsync();
        return updated;
    }

How can I get access to the method which called .saveChangesAsync so I know where it was triggered from? I've checked using StackTrace however that is flooded with library level frames which are not very helpful and I can't find the correct parent method.

I see in evt there is a that it provides a calling parent name, however that is just one level up so is just the "SaveChangesAsync" method.

Thanks

Jack
  • 2,891
  • 11
  • 48
  • 65
  • Does this answer your question? [How can I find the method that called the current method?](https://stackoverflow.com/questions/171970/how-can-i-find-the-method-that-called-the-current-method) – Svyatoslav Danyliv Jan 27 '23 at 15:36
  • @SvyatoslavDanyliv No I mentioned I used the stack trace (sorry called it stack frame). Will update that now. – Jack Jan 27 '23 at 15:42
  • 2
    Using `CallerMemberName` is a better idea. Walking the call stack is very expensive. That's not auditing anyway, that's application-level tracing. – Panagiotis Kanavos Jan 27 '23 at 15:58
  • That's what I'd like to use, but I don't know how I'm meant to apply it to the Audit.Core.Confirguration? – Jack Jan 27 '23 at 16:02
  • 1
    Even for tracing, it's a better idea to use the [built-in classes ActivitySource and Activity](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-instrumentation-walkthroughs). ASP.NET Core itself uses Activity for actions, which means you can already trace action calls. There's additional instrumentation for EF Core that only needs registering a package and a trace target, eg a file or a tracing server like Jaeger or Zipkin – Panagiotis Kanavos Jan 27 '23 at 16:02

1 Answers1

1

If you can change the code that calls SaveChangesAsync and you are inheriting your DbContext from AuditDbContext (High-Level SaveChanges interception), then you could add a new SaveChanges method with an optional parameter decorated with [CallerMemberName] and store the caller member name in a custom field of the AuditEvent.

For example:

public class YourDbContext : AuditDbContext
{
    public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default) 
        => throw new NotImplementedException("Should call SaveChangesAuditAsync");

    public Task<int> SaveChangesAuditAsync([CallerMemberName] string memberName = "", CancellationToken cancellationToken = default)
    {
        this.AddAuditCustomField("Caller", memberName);
        return base.SaveChangesAsync(cancellationToken);
    }
}

So, in your AuditEntityAction you can get the caller member name from the custom field:

    ...
    .AuditEntityAction<AuditLog>((evt, entry, auditEntity) =>
    {
        auditEntity.CallingMethod = evt.CustomFields["Caller"];
    })

Now your DoSomeWork() must call the new method:

public async Task DoSomeWork() 
{
    ...
    await dbConn.SaveChangesAuditAsync();
    return updated;
}
thepirat000
  • 12,362
  • 4
  • 46
  • 72