Более двадцати экземпляров IServiceProvider были созданы для внутреннего использования Entity Framework - PullRequest
0 голосов
/ 04 февраля 2020

Я получаю это предупреждение в моем ASP. NET Core 2.2 приложении

предупреждение: Microsoft.EntityFrameworkCore.Infrastructure [10402] Более двадцати экземпляров IServiceProvider было создано для внутреннее использование Entity Framework. Обычно это вызвано внедрением нового экземпляра одноэлементной службы в каждый экземпляр DbContext. Например, вызывая UseLoggerFactory, каждый раз передавая новый экземпляр - см. https://go.microsoft.com/fwlink/?linkid=869049 для получения дополнительной информации. Подумайте о проверке вызовов в DbContextOptionsBuilder, которые могут потребовать создания новых поставщиков услуг.

Потратив некоторое время, я выяснил, что происходит в startup.cs. Я использую IdentityServer3 + OpenIDCnnection для аутентификации.

После успешного входа пользователя клиентское приложение авторизует пользователя, убедившись, что пользователь существует в базе данных клиентского приложения.

Startup.cs клиентского приложения

public clas 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 Ответ

0 голосов
/ 04 февраля 2020

(1) Вместо удаления dbcontext вы можете определить аргумент ServiceLifetime метода AddDbContext.

contextLifetime: ServiceLifetime

Время жизни, с которым регистрируется служба DbContext в контейнер.

optionsLifetime: ServiceLifetime

Время жизни, с которым регистрируется служба DbContextOptions в контейнере.

EntityFrameworkServiceCollectionExtensions.AddDbContext Method

(2) Ниже приведен пример журнала и ловушки ошибок, которые могут применяться к методу configureservices в классе запуска.

using Microsoft.Extensions.Logging;
/* { your line codes here } */

   // 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 являются классами c для и объявление и время выполнения. Поэтому при изменении схемы базы данных вы должны изменить (или выполнить любые шаги по миграции) класс (ы).

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...