Entity Framework Core Pitfalls: Asynchronous vs Synchronous Calls and Interceptors

Introduction

Another on my EF Core pitfalls series. This time, interceptors and synchronous/asynchronous calls.

Problem

You surely know about EF Core interceptors, a very useful feature that I talked about many times. What's the problem with them? Well, all of the interceptor interfaces define both synchronous as well as asynchronous versions of their methods. This is so that, for example, when we call DbContext.SaveChanges the synchronous version is called, and when it's DbContext.SaveChangesAsync, the asynchronous one instead. I think you get the idea.

So, imagine we added an interceptor, inheriting from SaveChangesInterceptor, to our collection of interceptors. If we then commit the changes in the DbContext through a call to DbContext.SaveChanges, only SavingChanges, SavedChanges, SavedChangesFailedSaveChangedCanceled and, or, ThrowingConcurrencyException methods will be called, and you may be very surprised because your well-crafted asynchronous one wasn't.

Solution

Two possible solutions:

  1. Always make sure you call the same version of each operation, synchronous or asynchronous, and implement only the matching method on the interceptors consistently
  2. Have both versions call the same shared code, for example:
public override InterceptionResult<int> SavingChanges(DbContextEventData eventData, InterceptionResult<int> result)
{
    SaveChanges(eventData.Context);
    return base.SavingChanges(eventData, result);
}

public override ValueTask<InterceptionResult<int>> SavingChangesAsync(DbContextEventData eventData, InterceptionResult<int> result, CancellationToken cancellationToken))
{
    SaveChanges(eventData.Context);
    return base.SavingChangesAsync(eventData, result, cancellationToken);
}

private void SaveChanges(DbContext context)
{
    //where the magic actually happens
}

Conclusion

Hope you find this useful. Stay tuned for more!

Comments

Popular posts from this blog

OpenTelemetry with ASP.NET Core

ASP.NET Core Middleware

.NET Cancellation Tokens