Tag Archives: EntityFramework
Entity Framework Interceptors

I’ve recently published two NuGet packages that may be of interest to Entity Framework Code First users. The first is Isg.EntityFramework.Interceptors which provides an interface for intercepting operations during a call to DbContext.SaveChanges() and taking some action before or after. The 2nd package is Isg.EntityFramework.Interceptors.SoftDelete which provides a concrete implementation of an interceptor.

Using the interceptors library involves three steps.

1) Implement an interceptor.

2) Register your interceptors.

3) Subclass InterceptorDbContext

Implementing an Interceptor

Implementing an interceptor is very easy.  The IInterceptor has two methods—Before and After—each of which refer to the SaveChanges() method of DbContext.

 1:     public interface IInterceptor
 2:     {
 3:         void Before(InterceptionContext context);
 4:         void After(InterceptionContext context);
 5:     }

 

The InterceptionContext consists of information your interceptor may need. You get the InterceptorDbContext that is in the process of being saved, the ObjectContext, ObjectStateManager, DbChangeTracker, and list of DbEntityEntry objects that are participating in the operation.

A TypeInterceptor implementation is provided that filters for entities of a certain type. A ChangeInterceptor implementation is provided that filters entities being Added, Modified, or Deleted. The ChangeInterceptor provides Before and After methods that can be overridden for each of those operations.

Register Your Interceptors

Interceptor registration is easy. In the case of the SoftDeleteInterceptor, registration looks like this:

 1: InterceptorProvider.SetInterceptorProvider(
 2:     new DefaultInterceptorProvider(
 3:         new SoftDeleteChangeInterceptor()));

 

InterceptorProvider is a global cache of Interceptor instances that relies on a provider to resolve the instances. In this case, I am manually providing the SoftDeleteInterceptor, but you can plug in a dependency injection framework or any other source of providers that you prefer. If you do this at application startup, any instance of InterceptorDbContext will automatically pull in the Interceptors and apply them during the SaveChanges operation.

Subclass InterceptorDbContext

This one really is as easy as it sounds. Instead of inheriting directly from DbContext, inherit from InterceptorDbContext. For example:

 1:     public class CustomerDbContext : InterceptorDbContext
 2:     {
 3:         public DbSet<Invoice> Invoices { get; set; }
 4:         public DbSet<Customer> Customers { get; set; }
 5: 
 6:         protected override void OnModelCreating(DbModelBuilder modelBuilder)
 7:         {
 8:             base.OnModelCreating(modelBuilder);
 9: 
 10:             modelBuilder.Entity<Invoice>()
 11:                .HasKey(i => i.InvoiceId)
 12:                ;
 13:             modelBuilder.Entity<Invoice>()
 14:                 .HasRequired(invoice => invoice.Customer)
 15:                 .WithMany(customer => customer.Invoices)
 16:                 .HasForeignKey(i => i.CustomerId)
 17:                 ;
 18: 
 19:             modelBuilder.Entity<Customer>()
 20:                .HasKey(customer => customer.CustomerId)
 21:                ;
 22:         }
 23:     }

InterceptorDbContext will build the InterceptionContext object and pass it to your interceptors Before and After the SaveChanges method is called.

Your Input Matters

The current version of the libraries are 0.2.1. If there are other commonly used interceptor implementations that should be implemented I’ll be happy to create packages for those. If you have other feature requests for the package I’d love to hear them.