Introduction
When building applications with Entity Framework Core (EF Core), developers often need to execute custom logic during database operations.
Common requirements include:
Auditing changes
Logging SQL queries
Performance monitoring
Soft deletes
Data validation
Multi-tenant filtering
Traditionally, this logic was added directly inside services or repositories, leading to duplicated code and maintenance challenges.
EF Core Interceptors provide a cleaner solution by allowing developers to intercept and customize database operations before or after they execute.
In this article, you'll learn what EF Core Interceptors are, how they work, and explore practical real-world use cases with examples.
What Are EF Core Interceptors?
EF Core Interceptors are components that allow developers to intercept database operations and execute custom logic during the Entity Framework pipeline.
They act as middleware for EF Core operations.
Example flow:
Application
↓
EF Core
↓
Interceptor
↓
Database
Interceptors can inspect, modify, or react to operations before they reach the database.
Why Use Interceptors?
Consider an application where every database change must be audited.
Without interceptors:
Service A
↓
Audit Logic
Service B
↓
Audit Logic
Service C
↓
Audit Logic
The same code gets repeated.
With interceptors:
EF Core Interceptor
↓
Audit Logic
↓
All DbContext Operations
This centralizes behavior and reduces duplication.
Common Types of EF Core Interceptors
EF Core provides several interceptor types.
SaveChanges Interceptor
Triggers during:
Insert
Update
Delete
Useful for:
Auditing
Validation
Soft Deletes
Command Interceptor
Triggers when SQL commands execute.
Useful for:
SQL logging
Query analysis
Performance monitoring
Connection Interceptor
Triggers during database connections.
Useful for:
Connection tracking
Diagnostics
Monitoring
Creating a SaveChanges Interceptor
A common scenario is auditing.
Example:
using Microsoft.EntityFrameworkCore.Diagnostics;
public class AuditInterceptor
: SaveChangesInterceptor
{
public override ValueTask<
InterceptionResult<int>>
SavingChangesAsync(
DbContextEventData eventData,
InterceptionResult<int> result,
CancellationToken cancellationToken = default)
{
Console.WriteLine(
"Saving Changes");
return base.SavingChangesAsync(
eventData,
result,
cancellationToken);
}
}
This executes whenever SaveChanges() runs.
Registering an Interceptor
Register the interceptor in DbContext.
builder.Services
.AddDbContext<AppDbContext>(
options =>
{
options.UseSqlServer(
connectionString);
options.AddInterceptors(
new AuditInterceptor());
});
The interceptor now applies automatically.
Real-World Use Case: Auditing
Many applications need to track:
Who created a record
When it was created
Who modified it
When it was modified
Join the conversation! Your thoughts help the community grow.