Как логгировать в EntityFramework штатными средствами net core?

Написал логгер, провайдер, подключаю в Startup, из него же прокидываю экземпляр контекста.
Startup.cs

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory, SomeDbContext db)
        {
            ...
            loggerFactory.AddProvider(new DbLoggerProvider(db));
            ...
        {


DbLoggerProvider.cs

public class DbLoggerProvider: ILoggerProvider
    {
        private SomeDbContext _db;
        public DbLoggerProvider(SomeDbContext db)
        {
            _db = db;
        }
        public void Dispose()
        {
        }

        public ILogger CreateLogger(string categoryName)
        {
            return new DbLogger(_db);
        }
    }


DbLogger.cs

public class DbLogger: ILogger
    {
        private const LogLevel _minLevel = LogLevel.Debug;

        private SomeDbContext _db;

        public DbLogger(SomeDbContext db)
        {
            _db = db;
        }

        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            if (formatter == null) return;
            try
            {
                _db.Logs.Add(/*Some log data*/);
                _db.SaveChanges();
            }
            catch (Exception e)
            {
                // ignored
            }
        }

        public bool IsEnabled(LogLevel logLevel)
        {
            return logLevel >= _minLevel;
        }

        public IDisposable BeginScope<TState>(TState state)
        {
            return null;
        }
    }



Если смотреть через отладчик, то всё срабатывает как надо - логгер создаётся и подключается, в него прокидывается контекст БД. Но когда происходит событие Log, то контекст оказывается disposed. Почему так и как этого можно избежать?
  • Вопрос задан
  • 91 просмотр
Решения вопроса 1
byte916
@byte916 Автор вопроса
Если кратко, то логгер, судя по всему, синглтон, а БД по умолчанию не синглтон, и из-за этого возникает описанная проблема.
В общем, вот решение задачи.
Вместо контекста бд пробрасываем ServiceProvider
Startup.cs

loggerFactory.AddProvider(new DbLoggerProvider(app.ApplicationServices));


В логгере создаем scope и получаем из сервиспровайдера экземпляр БД
DbLogger.cs

using (var scope = _serviceProvider.CreateScope())
{
   var db = scope.ServiceProvider.GetRequiredService<CuDb>();

   db.Logs.Add(new CheckUpDb.Log() { Date = DateTime.UtcNow, LogLevel = logLevel, Message = formatter(state, exception) });
   db.SaveChanges();
}

Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы