EF Core Interceptors: SaveChangesInterceptor for Auditing Entities in .NET 8 Microservices

Mehmet Ozkaya
3 min readMar 27, 2024

We are going to develop EF Core Interceptors: SaveChangesInterceptor for Auditing Entities.

I have just published course — .NET 8 Microservices: C# 12, DDD, CQRS, Vertical/Clean Architecture.

Implementing EF Core SaveChangesInterceptor for Entity Auditing

Entity Framework Core (EF Core) introduces a powerful feature called Interceptors that allows developers to inject custom behavior into various stages of the EF Core operation pipeline. One particularly useful interceptor is the SaveChangesInterceptor, which provides hooks into the save changes operations of DbContext. This feature is incredibly beneficial for implementing auditing functionalities, where you need to track changes to entities, such as who created or modified an entity and when.

Understanding EF Core Interceptors

Interceptors in EF Core enable developers to intercept, modify, or even suppress operations executed by EF Core. This capability spans across a wide range of operations, from executing database commands to higher-level operations like saving changes to the database.

The Role of SaveChanges Interceptor

The SaveChangesInterceptor specifically targets the SaveChanges and SaveChangesAsync methods of DbContext, allowing developers to execute custom logic before or after changes are persisted to the database. This is facilitated by the ISaveChangesInterceptor interface, which defines interception methods for these operations.

Auditing with SaveChanges Interceptor

The interception of SaveChanges operations is particularly useful for auditing purposes. It allows developers to iterate through the entities tracked by DbContext that are pending changes and log necessary audit information such as timestamps or user identifiers before these changes are committed to the database.

Registering the SaveChanges Interceptor

Interceptors are registered with the DbContext configuration, typically within the OnConfiguring method or via the options builder in a DI setup. This ensures that the interceptor is engaged whenever the DbContext performs operations.

public class MyDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.AddInterceptors(new MySaveChangesInterceptor());
}

Creating a Custom SaveChanges Interceptor

To implement custom auditing logic, one can extend the SaveChangesInterceptor class or directly implement the ISaveChangesInterceptor interface. Overriding the SavingChanges and SavedChanges methods enables the execution of custom logic during the save changes operation.

For instance, an auditing interceptor might look like this:

public class AuditingSaveChangesInterceptor : SaveChangesInterceptor
{
public override InterceptionResult<int> SavingChanges(DbContextEventData eventData, InterceptionResult<int> result)
{
var dbContext = eventData.Context;
foreach (var entry in dbContext.ChangeTracker.Entries().Where(e => e.State == EntityState.Added || e.State == EntityState.Modified))
{
if (entry.Entity is AuditableEntity auditable)
{
if (entry.State == EntityState.Added)
{
auditable.CreatedAt = DateTime.UtcNow;
auditable.CreatedBy = // logic to fetch current user;
}
else if (entry.State == EntityState.Modified)
{
auditable.LastModified = DateTime.UtcNow;
auditable.LastModifiedBy = // logic to fetch current user;
}
}
}
return base.SavingChanges(eventData, result);
}
}

Conclusion

The SaveChangesInterceptor in EF Core is a robust tool for embedding auditing functionalities directly into the data persistence lifecycle. By leveraging this interceptor, developers can ensure that audit trails are consistently maintained across the application, providing a transparent and reliable record of entity changes. Integrating this into your EF Core configuration not only centralizes auditing logic but also enhances the maintainability and clarity of your application's data handling practices.

I have just published course — .NET 8 Microservices: C# 12, DDD, CQRS, Vertical/Clean Architecture.

This is step-by-step development of reference microservices architecture that include microservices on .NET platforms which used ASP.NET Web API, Docker, RabbitMQ, MassTransit, Grpc, Yarp API Gateway, PostgreSQL, Redis, SQLite, SqlServer, Marten, Entity Framework Core, CQRS, MediatR, DDD, Vertical and Clean Architecture implementation with using latest features of .NET 8 and C# 12.

--

--

Mehmet Ozkaya

Software Architect | Udemy Instructor | AWS Community Builder | Cloud-Native and Serverless Event-driven Microservices https://github.com/mehmetozkaya