In this lesson, you will learn how to automate audit trail management by intercepting the SaveChanges process in Entity Framework Core.
Why Intercept SaveChanges?
Every time you call SaveChanges() or SaveChangesAsync(), EF Core translates your C# object changes into SQL commands. Instead of manually setting CreatedDate, ModifiedBy, or AuditLog entries in every service method, you can hook into the EF Core pipeline to do this work automatically. This ensures your audit logic is centralized, consistent, and impossible to forget.
The Interceptor Pattern
To hook into this process, we create a class that implements ISaveChangesInterceptor. This interface provides methods like SavingChanges and SavingChangesAsync, which run before the SQL is sent to the database.
Here is how you can implement a simple interceptor to automatically stamp entries with a modification timestamp:
public class AuditInterceptor : SaveChangesInterceptor
{
public override ValueTask<InterceptionResult<int>> SavingChangesAsync(
DbContextEventData eventData,
InterceptionResult<int> result,
CancellationToken ct = default)
{
var context = eventData.Context;
var entries = context.ChangeTracker.Entries<IAuditable>();
foreach (var entry in entries)
{
if (entry.State == EntityState.Added)
{
entry.Entity.CreatedAt = DateTime.UtcNow;
}
entry.Entity.UpdatedAt = DateTime.UtcNow;
}
return base.SavingChangesAsync(eventData, result, ct);
}
}
Registering the Interceptor
Once your interceptor is defined, you need to register it within your DbContext configuration. You do this by overriding OnConfiguring:
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.AddInterceptors(new AuditInterceptor());
}
How it works
When you call SaveChanges, EF Core’s ChangeTracker inspects the entities being tracked. By filtering for entities that implement an interface (like IAuditable in the example above), the interceptor injects the necessary metadata automatically. Because this runs at the DbContext level, it applies regardless of whether your data modification happens in a controller, a background task, or a bulk update service.
Key Takeaway: SaveChanges Interception allows you to enforce cross-cutting concerns like auditing and data consistency globally, ensuring that every database save adheres to your business rules without polluting your application logic.