Fermin Perdomo

Senior Full Stack Engineer | PHP | JavaScript

How to Implement EF Core-Like Interceptors in .NET Framework with EF6

Fermin Perdomo
October 27, 2025

When working with .NET Core and EF Core, it's easy to plug in interceptors using the built-in AddDbContext and AddInterceptors methods:

services.AddDbContext<IApplicationDbContext, ApplicationDbContext>(
    (sp, options) => options
        .UseSqlServer(connectionString)
        .AddInterceptors(
            sp.GetRequiredService<UpdateAuditableInterceptor>(),
            sp.GetRequiredService<InsertOutboxMessagesInterceptor>()));

But what if you're working with a legacy .NET Framework 4.x project using Entity Framework 6.x?

In this post, I’ll show you how to implement similar behavior—using interceptors, dependency injection, and auditable logic—in a .NET Framework + EF6 setup.

Background: Interceptors in EF6 vs EF Core

FeatureEF Core (Modern)EF6 (in .NET Framework)
Interceptor support | AddInterceptors() (per context) | DbInterception.Add() (global)
Dependency Injection | Built-in with IServiceCollection | Manual or via DI container
SaveChanges Auditing | Supported via SaveChanges() | Supported via SaveChanges()


Goal

Recreate this EF Core-style setup in EF6:


services.AddSingleton<UpdateAuditableInterceptor>(); services.AddSingleton<InsertOutboxMessagesInterceptor>(); services.AddDbContext<IApplicationDbContext, ApplicationDbContext>( (sp, options) => options .UseSqlServer(connectionString) .AddInterceptors(...));

Step 1: Define EF6 Interceptors

In EF6, you can create interceptors by implementing interfaces like IDbCommandInterceptor.


public class UpdateAuditableInterceptor : IDbCommandInterceptor { public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { // Add your auditing logic here } // You can leave the rest of the methods empty if not needed public void NonQueryExecuting(...) { } public void ScalarExecuting(...) { } // etc. }

You can do the same for your InsertOutboxMessagesInterceptor.

Step 2: Register Interceptors with EF6

EF6 does not support context-scoped interceptors. Instead, use the static DbInterception class:

Option A: Global Registration in Global.asax.cs


protected void Application_Start() { DbInterception.Add(new UpdateAuditableInterceptor()); DbInterception.Add(new InsertOutboxMessagesInterceptor()); }

Option B: Register via Dependency Injection

If you’re using Microsoft.Extensions.DependencyInjection (or any DI container), you can do this:


var services = new ServiceCollection(); services.AddSingleton<UpdateAuditableInterceptor>(); services.AddSingleton<InsertOutboxMessagesInterceptor>(); services.AddScoped<ApplicationDbContext>(provider => { var interceptor1 = provider.GetRequiredService<UpdateAuditableInterceptor>(); var interceptor2 = provider.GetRequiredService<InsertOutboxMessagesInterceptor>(); DbInterception.Add(interceptor1); DbInterception.Add(interceptor2); return new ApplicationDbContext("YourConnectionString"); });
⚠️ Important: EF6 interceptors are global and affect all DbContext instances in the AppDomain.

Bonus: SaveChanges Auditing Without Interceptors

For simple audit tracking like setting UpdatedAt timestamps, it's better to override SaveChanges() in your context:


public override int SaveChanges() { var entries = ChangeTracker.Entries<IAuditableEntity>(); foreach (var entry in entries) { if (entry.State == EntityState.Modified) { entry.Entity.UpdatedAt = DateTime.Now; } } return base.SaveChanges(); }

This is cleaner, more predictable, and avoids EF6 interceptor quirks.

Testing It All

Make sure to test with:

  • Inserts and updates for auditable entities
  • Scenarios where interceptors may not fire (e.g., raw SQL)
  • Multi-threaded contexts if using global interceptors

Summary

You can mimic EF Core's AddInterceptors() in EF6, but with some caveats:

  • Interceptors are global in EF6.
  • Manual DI setup is required.
  • For auditing, overriding SaveChanges() is often simpler and safer.

If you're maintaining a .NET Framework project but want to adopt some clean patterns from EF Core, this approach will help bridge that gap.


Reactions

Loading reactions...
Log in to react to this post.

Comments

Please login to leave a comment.

Newsletter