一个 ASP.NET Core 2.2 的项目在运行集成测试时出现下面的告警:
More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. This is commonly caused by injection of a new singleton service instance into every DbContext instance. For example, calling UseLoggerFactory passing in a new instance each time--see https://go.microsoft.com/fwlink/?linkid=869049 for more details. Consider reviewing calls on 'DbContextOptionsBuilder' that may require new service providers to be built.
请问如何解决?
查看 EF Core 2.2 源码,告警日志是在 ServiceProviderCache.cs#L115 中写的
var logger = serviceProvider.GetRequiredService<IDiagnosticsLogger<DbLoggerCategory.Infrastructure>>();
if (_configurations.Count == 0)
{
logger.ServiceProviderCreated(serviceProvider);
}
else
{
logger.ServiceProviderDebugInfo(
debugInfo,
_configurations.Values.Select(v => v.DebugInfo).ToList());
if (_configurations.Count >= 20)
{
logger.ManyServiceProvidersCreatedWarning(
_configurations.Values.Select(e => e.ServiceProvider).ToList());
}
}
是在测试类中手动 new WebApplicationFactory<Startup> 引起的
public class ApiPostsControllerTests : IClassFixture<BlogServerAdminAppFactory>
{
private readonly BlogServerAdminAppFactory _fixture;
public ApiPostsControllerTests()
{
_fixture = new BlogServerAdminAppFactory();
}
}
上面的代码中 BlogServerAdminAppFactory 继承自 WebApplicationFactory<Startup>
改为通过构造函数依赖注入 BlogServerAdminAppFactory ,告警就消失了
public class ApiPostsControllerTests : IClassFixture<BlogServerAdminAppFactory>
{
private readonly BlogServerAdminAppFactory _fixture;
public ApiPostsControllerTests(BlogServerAdminAppFactory fixture)
{
_fixture = fixture;
}
}
通过 IClassFixture 依赖注入,同一个 Class 的所有 Fact 共享一个 BlogServerAdminAppFactory 实例,而手动 new ,每一个 Fact 都使用一个新建的 BlogServerAdminAppFactory 实例
可以用这里介绍的方式来禁止 EF Core 创建 IServiceProvider
https://github.com/aspnet/EntityFrameworkCore/issues/12440#issuecomment-399158858