Perhaps having dependency injection in .Net for fifteen years has spoilt us a little. We expect any class to simply declare some dependency or other as a constructor parameter and by DI magic it all just works.
It doesn't work for everything though. Notably, it doesn't ‘just work’ in the dependency injection factories provided by Microsoft for EntityFramework. The DI factory .AddDbContext<T>(...) method expects your constructor to take a single DbContextOptions<T> options parameter. No other dependencies can be declared.
The injection technique offered instead by Entity Framework is to add IDbContextOptionsExtension instances to the DbContextOptions. This requires some boilerplate.
The Problem
You use microsoft.extensions.dependencyinjection. You use EntityFrameworkCore. You want to inject dependencies into a DbContext created by the DI factory. You can’t add constructor parameters. How to do it?
How To Create and Use an IDbContextOptionsExtension
As best I can see, the boilerplate for this is about five separate pieces of code. The final piece is a single line in your DI setup, in the same place you add out-of-the-box extensions like EnableDetailErrors:
services.AddDbContext<MyApplicationsDbContext>(
(s,o) => {
o.UseSqlServer(dbString)
.EnableDetailedErrors()
.EnableSensitiveDataLogging(isDevOrTest)
// -----------------------------------------
// 👇 add one line to inject your dependency
.InjectMyThings( s.GetRequiredService<ThingToInject>() );
// 👆 --------------------------------------
});
The Boilerplate
To make that one line work, you write four more pieces of code.
1. The DbContextOptionsBuilder extension method
/// <summary>
/// Boilerplate to make <see cref="DbOptionsMyInjectedThingExtension"/> available.
/// </summary>
public static class MyInjectedThingExtensionDbContextOptionsBuilderExtensions
{
public static DbContextOptionsBuilder InjectMyThings(this DbContextOptionsBuilder builder, ThingToInject myInjectedThing)
{
(builder as IDbContextOptionsBuilderInfrastructure)
.AddOrUpdateExtension(new DbOptionsMyInjectedThingExtension(myInjectedThing));
return builder;
}
}
2. Your custom IDbContextOptionsExtension class which holds the dependencies to inject
/// <summary>
/// Add MyInjectedThing to the <see cref="DbContextOptions"/>.
/// </summary>
public class DbOptionsMyInjectedThingExtension : IDbContextOptionsExtension
{
///<summary>This class carries the thing you want to inject</summary>
public bool MyInjectedBool { get; }
public ThingToInject EvenMoreInjectedThings { get; }
public DbOptionsMyInjectedThingExtension(ThingToInject myInjectedThing)
{
MyInjectedBool = myInjectedThing.MyInjectedBool;
EvenMoreInjectedThings = myInjectedThing;
Info = new DbOptionsMyInjectedThingExtensionInfo(this);
}
public void ApplyServices(IServiceCollection services)
{
services.AddSingleton(this);
}
public void Validate(IDbContextOptions options) { }
public DbContextOptionsExtensionInfo Info { get; }
}
3. The EFCore MetaData
/// <summary>
/// Boilerplate to make <see cref="DbOptionsMyInjectedThingExtension"/> available.
/// </summary>
public class DbOptionsMyInjectedThingExtensionInfo : DbContextOptionsExtensionInfo
{
/// <inheritdoc/>
public DbOptionsMyInjectedThingExtensionInfo(DbOptionsMyInjectedThingExtension extension) : base(extension) { }
/// <inheritdoc/>
public override bool IsDatabaseProvider => false;
/// <inheritdoc/>
public override string LogFragment => "MyInjectedThing: {MyInjectedThing}";
/// <inheritdoc/>
public override int GetServiceProviderHashCode() => 0;
/// <inheritdoc/>
public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other)
=> (other.Extension as DbOptionsMyInjectedThingExtension)?.MyInjectedBool == (Extension as DbOptionsMyInjectedThingExtension)?.MyInjectedBool;
/// <inheritdoc/>
public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
{
debugInfo["MyInjectedThing:"] = $"MyInjectedThing={(Extension as DbOptionsMyInjectedThingExtension)}";
}
}
4. Finally, your DbContext constructor
public MyApplicationsDbContext(DbContextOptions<MyApplicationsDbContext> options)
: base(options)
{
MyInjectedThing = options.FindExtension<DbOptionsMyInjectedThingExtension>()?.EvenMoreInjectedThings;
MyInjectedBool = EvenMoreInjectedThings?.MyInjectedBool ?? false ;
}
protected bool MyInjectedBool;
protected ThingToInject MyInjectedThing;

Amazon (UK)