entity-framework-core - 已创建超过 20 个 'IServiceProvider' 实例供 Entity Framework 内部使用

标签 entity-framework-core ef-core-2.0 ef-core-2.2 ef-core-2.1

我在我的 ASP.NET Core 2.2 应用程序中收到此警告

warn: Microsoft.EntityFrameworkCore.Infrastructure[10402] 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.

花了一些时间后,我发现它发生在 startup.cs 中。我正在使用 IdentityServer3 + OpenIDCNnection 进行身份验证。

用户成功登录后,客户端应用程序授权用户确保用户存在于客户端应用程序的数据库中。

客户端应用的Startup.cs

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped<IAccountService, AccountService>();
        services.AddDbContext<Data.Entities.MyDBContext>(options =>
        {
            options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"), 
                sqlServerOptions => sqlServerOptions.CommandTimeout(sqlCommandTimeout));
        });
    
        services.AddAuthentication(options =>
            {
                // removed for brevity purpose
            })
            .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
            {
                // removed for brevity purpose
            })
            .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
            {
           
                options.Events = new OpenIdConnectEvents()
                {
                    OnTokenValidated = async context =>
                    {
                        Data.Entities.UserAccount userAccount = null;
                        using (var serviceProvider = services.BuildServiceProvider())
                        {
                            using (var serviceScope = serviceProvider.CreateScope())
                            {
                                using (var accountService = serviceScope.ServiceProvider.GetService<IAccountService>())
                                {
                                    userAccount = await accountService.Authorize(userName);
                                }
                            }
                        }

                        if (userAccount == null)
                        {
                            throw new UnauthorizedAccessException(string.Format("Could not find user for login '{0}' ", userName));
                        }                         
                    },                     
                };
            }
        );
    }
}

账户服务

public class AccountService : IAccountService
{
    private bool _disposed = false;
    private readonly MyDBContext_dbContext;

    public AccountService(MyDBContext dbContext)
    {
        _dbContext = dbContext;     
    }

    public UserAccount Authorize(string userName)
    {
        // Ensures user exists in the database
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
            return;

        if (disposing)
        {
            if (_dbContext != null)
            {
                _dbContext.Dispose();
            }
            // Free any other managed objects here.                    
        }

        // Free any unmanaged objects here.
        _disposed = true;
    }   
}

AccountService.Authorize(userName) 将在每次成功登录时被调用。以此类推,第 21 位成功用户及以后我开始看到警告。

问题

1>在 OnTokenValidated 事件中,我正在创建服务提供者并立即处置它。为什么 EF 还在记录警告?
2>如何摆脱这个警告?

即使我使用范围创建 20 多个 DBContext,我也会收到此警告

NET Fiddle DEMO

最佳答案

(1) 您可以定义 AddDbContext 方法的 ServiceLifetime 参数,而不是处理 dbcontext。

contextLifetime: ServiceLifetime

The lifetime with which to register the DbContext service in the container.

optionsLifetime : ServiceLifetime

The lifetime with which to register the DbContextOptions service in the container.

EntityFrameworkServiceCollectionExtensions.AddDbContext Method

(2) 下面是logger和error trap的例子,可以用在启动类的configureservices方法上。

// define single service provider
 using (var sp = new ServiceCollection()
                   .AddLogging(l => l.AddConsole())
                   .AddDbContext<MyDBContext>(options =>
                    {
                        options.UseSqlServer("Server=(local);Database=MyDB;Integrated Security=True",
                        sqlServerOptions => sqlServerOptions.CommandTimeout(120));
                     })
                    .BuildServiceProvider())
 
 // define service logger
 using (var logger = sp.GetService<ILoggerFactory>().CreateLogger<Program>())
 {
      try
      {
          for (int i = 1; i <= 25; i++)
          {
              using (var serviceScope = sp.CreateScope())
              using (var accountService = sp.GetService<MyDBContext>())
              {
                  
              }
          }
      }

     // (2) catch the error warning
     catch(ex: Exception)
     {
          logger.LogInformation($@"Error: {ex.ToString()}");
     }
 }

顺便说一句,EF 实体绝对是声明和运行时的静态类。因此,您必须在数据库架构更改时修改(或执行任何迁移步骤)类。

希望这对您有所帮助。

关于entity-framework-core - 已创建超过 20 个 'IServiceProvider' 实例供 Entity Framework 内部使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60047465/

相关文章:

c# - 简化 Entity Framework Core 查询

c# - Expression.Convert() 对于 EF Core 中的日期时间数据类型无法正常工作

c# - 如何使用 Ef Core 将集合封装到 "complex type"对象中(包含示例)

c# - 如何在 Entity Framework 核心中使用泛型类型?

c# - .NET 标准的 System.Data.SqlClient 出错

entity-framework-migrations - EF Core 反复创建相同的迁移,更改标识列并且不做任何更改

.net-core - 为什么 "dotnet ef migrations add"会抛出 Win32Exception?

entity-framework - Entity Framework 核心层次结构ID

c# - 为什么 Entity Framework Core 一对多关系只创建左连接? IsRequired 不起作用

c# - EF Core 2.1 启动缓慢