How to inject the dbContext into iLogger

0

I trying to inject the ApplicationDbcontext into iLogger.

When I use _context variable inside the CustomLoggerProvider or CustomLoggerExtension it'is work.

While when the software CreateLogger create a instance of CustomLogger, I have a problem with ApplicationDbContext, when I use the _context variable to access the database the application crashes and doesn't work.

The following there is the error log:

System.ObjectDisposedException HResult=0x80131622 Messaggio=Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.

Origine=Microsoft.EntityFrameworkCore Analisi dello stack: at Microsoft.EntityFrameworkCore.DbContext.CheckDisposed() at Microsoft.EntityFrameworkCore.DbContext.Add[TEntity](TEntity entity)
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet1.Add(TEntity entity) at Application.Services.EventLogDB.saveInDb(Cliente c) 28 at Application.Models.DbLogger.CustomLogger.Log[TState](LogLevel logLevel, EventId eventId, TState state, Exception exception, Func3 formatter) in C:\Users......\Models\DbLogger\CustomLogger.cs:line 122 at Microsoft.Extensions.Logging.Logger.g__LoggerLog|12_0[TState](LogLevel logLevel, EventId eventId, ILogger logger, Exception exception, Func3 formatter, List1& exceptions, TState& state)

I think it's a problem of the service life cycle.

Is there anyone who knows a solution?

Startup.cs :

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
        services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddControllersWithViews();

        services.AddRazorPages();

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

        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory, IServiceProvider serviceProvider)
{
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
            endpoints.MapRazorPages();
        });

        var serviceHttp = serviceProvider.GetService<IHttpContextAccessor>();
        var serviceDbContext = serviceProvider.GetService<GestionaleOfficinaContext>();

        // THIS IS METHOD THAT SHOWS THE BAD BEHAVIOUR
        // Inside logger I need of Http context service and applicationDbContext
        loggerFactory.AddCustomLogger(serviceHttp, serviceDbContext);
    }
}

CustomLogger.cs :

public static class CustomLoggerExtensions
{
    public static ILoggerFactory AddCustomLogger(this ILoggerFactory factory, IHttpContextAccessor accessor, ApplicationDbContext_context,
                                          Func<string, LogLevel, bool> filter = null)
    {
        factory.AddProvider(new CustomLogProvider(filter, accessor, _context));
        return factory;
    }
}

public class CustomLogProvider : ILoggerProvider
{
    private readonly Func<string, LogLevel, bool> _filter;
    private readonly IHttpContextAccessor _accessor;
    private readonly ApplicationDbContext_context;

    public CustomLogProvider(Func<string, LogLevel, bool> filter, IHttpContextAccessor accessor, ApplicationDbContext context)
    {
        _filter = filter;
        _accessor = accessor;
        _context = context;

        // IF I USE THE variable _context in this place of code the applicationDbContext is available
        // and so the behaviour is right

        //if (_context != null)
        //{
        //    Cliente cl = new Cliente();
        //    cl.codiceFiscale = "ALFA";
        //
        //    _context.Add(cl);
        //    _context.SaveChanges();
        //}

    }

    public ILogger CreateLogger(string categoryName)
    {
        // In this part of code there is the strange behaviour
        // _context is different by null, but when I use _context
        // the lifetime of service ApplicationDbContext is END
        if (_context != null)
        {
            Cliente cl = new Cliente();
            cl.codiceFiscale = "CCC";

            _context.Add(cl);
            _context.SaveChanges();
        }

        return new CustomLogger(categoryName, _filter, _accessor, _context);
    }

    public void Dispose()
    {
        //base.Dispose();
    }
}

// THE ERROR IS IN THIS CLASS
public class CustomLogger : ILogger
{
    private string _categoryName;
    private Func<string, LogLevel, bool> _filter;
    private readonly IHttpContextAccessor _accessor;
    private readonly GestionaleOfficinaContext _context;

    public CustomLogger(string categoryName, Func<string, LogLevel, bool> filter, IHttpContextAccessor accessor, GestionaleOfficinaContext context)
    {
        _categoryName = categoryName;
        _filter = filter;
        _accessor = accessor;
        _context = context;
    }

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

    public bool IsEnabled(LogLevel logLevel)
    {
        return (_filter == null || _filter(_categoryName, logLevel));
    }

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    {
        if (!IsEnabled(logLevel))
        {
            return;
        }

        if (formatter == null)
        {
            throw new ArgumentNullException(nameof(formatter));
        }

        var message = formatter(state, exception);

        if (string.IsNullOrEmpty(message))
        {
            return;
        }

        message = $"{ logLevel }: {message}";
        // your implementation
    }
}
c#
asp.net
asp.net-mvc
web-services
dependency-injection
asked on Stack Overflow Oct 19, 2019 by Davide • edited Oct 20, 2019 by Max

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0