EF Core Query interceptor
Query interceptor in EF core allows developer to intercept the query before or after the execution. This provides the ability of interception, modification, or suppression of the query execution.
How to use Query Interceptor into code
EF core exposes DbCommandInterceptor
base class, this base class is abstract class and has overridable methods which could be hooked into a class which is inherited DbCommandInterceptor
class. Since Entity framework internally uses ADO.NET for database operations, DbCommandInterceptor
class provides lifecycle methods for a query.
Code example
Create a class that inherits DbCommandInterceptor
public class QueryInterceptor :DbCommandInterceptor {
}
Override the lifecycle method which you are interested in
public class QueryInterceptor :DbCommandInterceptor {
// runs before a query is executed
public override InterceptionResult<DbDataReader> ReaderExecuting(DbCommand command,CommandEventData eventData, InterceptionResult<DbDataReader> result){
Console.WriteLine($"Before Query execution. Query : {command.CommandText}");
return result;
}
// runs after a query is excuted
public override DbDataReader ReaderExecuted(DbCommand command, CommandExecutedEventData eventData, DbDataReader result) {
Console.WriteLine($"After Query execution. Query : {command.CommandText}");
return result;
}
}
DbCommandInterceptor
provides async version of these methods to support asynchronous operations
public class QueryInterceptor :DbCommandInterceptor {
public override ValueTask<InterceptionResult<DbDataReader>> ReaderExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result, CancellationToken cancellationToken = default){
return base.ReaderExecutingAsync(command, eventData, result, cancellationToken);
}
public override ValueTask<DbDataReader> ReaderExecutedAsync(DbCommand command, CommandExecutedEventData eventData, DbDataReader result, CancellationToken cancellationToken = default){
return base.ReaderExecutedAsync(command, eventData, result, cancellationToken);
}
}
Register the interceptor with DbContext:
An interceptor could be added to context using two ways :
register while adding DbContext to services
services.AddDbContext<ExampleContext>(opt => opt.UseNpgsql(cfg.GetConnectionString("DefaultConnectionString")) .AddInterceptors (new QueryInterceptor()));
register inside
OnConfiguring
method of DbContext classpublic class ExampleContext : DbContext{ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){ base.OnConfiguring(optionsBuilder); optionsBuilder.AddInterceptors(new QueryInterceptor()) } }
List of lifecycle methods available
Method Name | Description |
CommandCanceled , CommandCanceledAsync | called when a command is cancelled. |
CommandCreated | After command creation but before execution. |
[CommandCreating](learn.microsoft.com/en-us/dotnet/api/micros..) | Before a command is created |
CommandFailed, CommandFailedAsync | Called when execution of a command has failed with an exception. |
CommandInitialized | Called after EF has initialized CommandText and other command configuration. |
DataReaderClosing, DataReaderClosingAsync | Called just before EF intends to call Close(). |
DataReaderDisposing | Called when execution of a DbDataReader is about to be disposed. |
NonQueryExecuted, NonQueryExecutedAsync | Called immediately after EF calls ExecuteNonQuery(). |
[NonQueryExecuting](learn.microsoft.com/en-us/dotnet/api/micros..), [NonQueryExecutingAsync](learn.microsoft.com/en-us/dotnet/api/micros..) | Called just before EF intends to call ExecuteNonQuery(). |
ReaderExecuted, ReaderExecutedAsync | Called immediately after EF calls ExecuteReader(). |
[ReaderExecuting](learn.microsoft.com/en-us/dotnet/api/micros..), [ReaderExecutingAsync](learn.microsoft.com/en-us/dotnet/api/micros..) | Called just before EF intends to call ExecuteReader(). |
ScalarExecuted, ScalarExecutedAsync | Called immediately after EF calls ExecuteScalar(). |
[ScalarExecuting](learn.microsoft.com/en-us/dotnet/api/micros..), [ScalarExecutingAsync](learn.microsoft.com/en-us/dotnet/api/micros..) | Called just before EF intends to call ExecuteScalar(). |