I'm not sure my problem related to Dependency Injection, AutoFac, EF Core or dotnet. But stack trace gives me Microsoft.Extensions.DependencyInjection so i tend to send it here.
I had dotnet core webapi 2.2 project. Have updated it and all libraries to dotnet 5.0 and got drastically reduced perfomance on all DI resolve actions, but the most important problem with slow resolving DbContext.
I have 2 DbContext: RW and RO. RW Is initialized with AddDbContext function with singleton DbContextOptionsReader. RO context is initialized with Scoped instance of its OptionsReader. It gives huge resolve speed difference. If register it as Singleton as well - speed becomes the same.
Startup.cs
public override void ConfigureCollection()
{
ServiceCollection.AddSingleton<DbConnectionOptionsReader>();
ServiceCollection.AddScoped<DbRoConnectionOptionsReader>(); // i need it to be scoped
ServiceCollection.AddDbContext<DbContext>(SettingsRw);
ServiceCollection.AddDbContext<DbContextRo>(SettingsRo);
private void SettingsRw(IServiceProvider provider, DbContextOptionsBuilder builder)
{
var dbOptionsReader = provider.GetRequiredService<DbConnectionOptionsReader>();
builder.UseNpgsql(dbOptionsReader.ReadConnectionString(),
opts =>
{
// some code
});
}
private void SettingsRo(IServiceProvider provider, DbContextOptionsBuilder builder)
{
var dbOptionsReader = provider.GetRequiredService<DbRoConnectionOptionsReader>();
builder.UseNpgsql(dbOptionsReader.ReadConnectionString(), opts =>
{
// some code
}
}
}
public class DbConnectionOptionsReader
{
// 2 dependecies only, both are Singletones
public DbConnectionOptionsReader(IEnvContext envContext, IConfigurationRoot configRoot)
{
EnvContext = envContext;
ConfigRoot = configRoot;
}
// skipped
}
public class DbRoConnectionOptionsReader : DbConnectionOptionsReader, IGetRoConnection
{
// lot of dependencies
public DbRoConnectionOptionsReader(IEnvContext envContext,
IConfigurationRoot configRoot,
IDoAllowRoRequest doAllowRoRequest,
ILogger<DbRoConnectionOptionsReader> logger,
IGetReplicationConnection getReplicationConnection,
IGetRwForcer getRwForcer) : base(envContext, configRoot)
{
_doAllowRoRequest = doAllowRoRequest;
_logger = logger;
_getReplicationConnection = getReplicationConnection;
_getRwForcer = getRwForcer;
}
// skipped
}
Test code:
[Route("api/Sandbox3/[action]")]
public class Sandbox3Controller : Controller
{
private readonly IServiceProvider _serviceProvider;
public Sandbox3Controller(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
// GET
public IActionResult MeasureDbContextTime()
{
var dt1 = DateTime.Now;
var _ = _serviceProvider.GetRequiredService<DbContext>().SystemParameter.Count();
var dt2 = DateTime.Now - dt1;
var dt11 = DateTime.Now;
var __ = _serviceProvider.GetRequiredService<DbContextRo>().SystemParameter.Count();
var dt22 = DateTime.Now - dt11;
return Ok(
new
{
DbRwTime = dt2,
DbRoTime = dt22
});
}
}
Results:
dotnet 2.2 before upgrade
{
"DbRwTime": "00:00:00.0079315",
"DbRoTime": "00:00:00.0079183"
}
Perfect!
Upgraded 2.2 to dotnet5 project
{
"DbRwTime": "00:00:00.0429624",
"DbRoTime": "00:00:00.2241661" -- RO is very slow
}
RW x6 times slower!
RO x32 times slower!!
For experiment i created fresh dotnet 5 project and copypasted necessary parts for run (program.cs, startup.cs, both dbcontexts)
{
"DbRwTime": "00:00:00.0198894",
"DbRoTime": "00:00:00.0260551",
"ResolveTime": "00:00:00.0000769"
}
RW x2 times slower than 2.2
RO x4 times slower than 2.2
But RO is still much better than my upgraded 5.0 project, 0.02 sec vs 0.2 sec.
I'd like to achive clean 5.0 results at least for the first time. So i have to understand why RO is so low on upgraded project.
I've measured traces via jetbrains dotpeak:
Here is comparison of stack traces of DbContext's Count() function

You can see fast method (upper) goes via TryAddCoreServices and ends pretty fast
Slow method (lower) goes via DynamicServiceProviderEngine and lasts so long.
Tell me please, in which conditions code may go 1 or 2 way?
I use Autofac and part of registrations goes via Autofac, another part - via IServiceCollection
dotnet 5.0.5 x64
Entity Framework 5.0.5
Autofac 6.1.0
Autofac.Extensions.DependencyInjection 7.1.0
Debug/Release project mode doesnt matter. I've tried downgrade to dotnet 3.1 and the problem is still there. So it occured during 2.2 -> 3.1 transition
I'm not sure my problem related to Dependency Injection, AutoFac, EF Core or dotnet. But stack trace gives me Microsoft.Extensions.DependencyInjection so i tend to send it here.
I had dotnet core webapi 2.2 project. Have updated it and all libraries to dotnet 5.0 and got drastically reduced perfomance on all DI resolve actions, but the most important problem with slow resolving DbContext.
I have 2 DbContext: RW and RO. RW Is initialized with AddDbContext function with singleton DbContextOptionsReader. RO context is initialized with Scoped instance of its OptionsReader. It gives huge resolve speed difference. If register it as Singleton as well - speed becomes the same.
Test code:
Results:
dotnet 2.2 before upgrade
Perfect!
Upgraded 2.2 to dotnet5 project
RW x6 times slower!
RO x32 times slower!!
For experiment i created fresh dotnet 5 project and copypasted necessary parts for run (program.cs, startup.cs, both dbcontexts)
RW x2 times slower than 2.2
RO x4 times slower than 2.2
But RO is still much better than my upgraded 5.0 project, 0.02 sec vs 0.2 sec.
I'd like to achive clean 5.0 results at least for the first time. So i have to understand why RO is so low on upgraded project.
I've measured traces via jetbrains dotpeak:
Here is comparison of stack traces of DbContext's Count() function

You can see fast method (upper) goes via TryAddCoreServices and ends pretty fast
Slow method (lower) goes via DynamicServiceProviderEngine and lasts so long.
Tell me please, in which conditions code may go 1 or 2 way?
I use Autofac and part of registrations goes via Autofac, another part - via IServiceCollection
dotnet 5.0.5 x64
Entity Framework 5.0.5
Autofac 6.1.0
Autofac.Extensions.DependencyInjection 7.1.0
Debug/Release project mode doesnt matter. I've tried downgrade to dotnet 3.1 and the problem is still there. So it occured during 2.2 -> 3.1 transition