0

I have created a custom logger that logs to database. The issue I am facing is that when I run my migration, there is a conflict between the AppDbContext and MyLoggerProvider service. It seems that the issue is caused by the fact that the MyLoggerProvider is a singleton service, while the AppDbContext service is a scoped service.

How can I fix this issue to be able to run my migration successfully?

Program.cs:

builder.Services.AddDbContext<AppDbContext>(options =>
{
    options.UseSqlite(builder.Configuration.GetConnectionString("AppDbConnection"));
});

builder.Services.AddLogging();
builder.Services.AddSingleton<ILoggerProvider, MyLoggerProvider>();

MyLoggerProvider.cs:

public class MyLoggerProvider : ILoggerProvider
{
    private readonly AppDbContext dbContext;
    private readonly LogLevel minLevel = LogLevel.Information;

    public MyLoggerProvider(AppDbContext dbContext)
    {
        this.dbContext = dbContext;
    }

    public ILogger CreateLogger(string categoryName)
    {
        return new MyLogger(minLevel, dbContext);
    }

    // rest of the code
}

MyLogger.cs:

public class MyLogger : ILogger
{
    private readonly AppDbContext dbContext;
    private readonly LogLevel minLevel;

    public MyLogger(LogLevel minLevel, AppDbContext dbContext)
    {
        this.minLevel = minLevel;
        this.dbContext = dbContext;
    }

    // rest of the code
}

Update:

I used IServiceScopeFactory to access the DbContext service as shown in the updated code below:

public class MyLoggerProvider : ILoggerProvider
{
    private readonly LogLevel minLevel = LogLevel.Information;
    private readonly IServiceScopeFactory scopeFactory;

    public MyLoggerProvider(IServiceScopeFactory scopeFactory)
    {
        this.scopeFactory = scopeFactory;
    }

    public ILogger CreateLogger(string categoryName)
    {
        using (var scope = scopeFactory.CreateScope())
        {
            var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
            return new MyLogger(minLevel, dbContext);
        }
    }

    public void Dispose(){}
}

I thought this would work, but it times out when creating the migration.

An error occurred while accessing the Microsoft.Extensions.Hosting services. Continuing without the application service provider. Error: Timed out waiting for the entry point to build the IHost after 00:05:00. This timeout can be modified using the 'DOTNET_HOST_FACTORY_RESOLVER_DEFAULT_TIMEOUT_IN_SECONDS' environment variable.
Unable to create an object of type 'AppDbContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
Ibrahim Timimi
  • 2,656
  • 5
  • 19
  • 31

1 Answers1

1

Either modify your logger service to be Scoped, or setup your db context to be transient:

services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")), 
                ServiceLifetime.Transient, 
             ServiceLifetime.Transient);

Or see more solutions here: Use DbContext in ASP .Net Singleton Injected Class

LazZiya
  • 5,286
  • 2
  • 24
  • 37
  • Making DbContext a `Transient` service is not efficient I believe. Additionally, I believe `ILoggerProvider` should be singleton. I managed to get some ideas from the link you posted. Still no success. Thank you for the information. – Ibrahim Timimi Jan 02 '23 at 19:47
  • [using db context factory](https://learn.microsoft.com/en-us/ef/core/dbcontext-configuration/#using-a-dbcontext-factory-eg-for-blazor) could be an option. – LazZiya Jan 03 '23 at 05:59