Home > other >  ASP.NET: ILoggerProvider Singleton Service in Conflict with DbContext
ASP.NET: ILoggerProvider Singleton Service in Conflict with DbContext

Time:01-03

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

CodePudding user response:

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

CodePudding user response:

If the problem is regarding manual migration and you are using EF Core. When you are dealing with more than one DbContext, is required to specify to which DbContext will you make the migration.

Using multiple context types - Documentation

Add-Migration InitialCreate -Context AppContext
Add-Migration InitialCreate -Context MyLoggerProvider
  • Related