T0bi
T0bi

Reputation: 371

IHostedService Error in ASP.NET Core app - why is the object already disposed?

I have created a Background Service in my Server Solution

public class PurgeService : IHostedService, IDisposable
{
    private readonly IServiceProvider _provider;
    private Timer timer;
    public PurgeService(IServiceProvider serviceProvider)
    {
        using (IServiceScope scope = serviceProvider.CreateScope())
        {
            _provider = scope.ServiceProvider;
        }
    }

    public void Dispose()
    {
        timer?.Dispose();
    }

    public Task Purge(IServiceProvider serviceProvider)
    {
        var dbcontext = serviceProvider.GetRequiredService<ApplicationDBContext>();
        var setting = dbcontext.AppSet.First();
        double deletetime = setting.PurgeTimer *(1);
        DateTime deletedate = DateTime.Now.AddHours(deletetime);
        string deleteSQL = $"DELETE FROM Notifications WHERE CreatedDate > {deletedate}"
    }
    public Task StartAsync(CancellationToken cancellationToken)
    {
        timer = new Timer(x => Purge(_provider), null, TimeSpan.Zero, TimeSpan.FromSeconds(10));
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }

}

And added it to the Startup.cs

services.AddHostedService<PurgeService>();

My goal is to have a background service that checks every 10 seconds if there are notifications older than allowed and deletes them.

But when I run the app an error occurs

"System.ObjectDisposedException: "Cannot access a disposed object."

How can I implement this correctly?

Upvotes: 2

Views: 767

Answers (2)

T0bi
T0bi

Reputation: 371

The problem was that the database table was empty, but the null exception threw a completely different exception.

Upvotes: -1

Kit
Kit

Reputation: 21699

Your constructor seems to be establishing a scope, and immediately disposing the scope. Your provider is tied to that scope so gets nuked immediately in the constructor when Dispose() is called on the scope due to using.

Background services are usually singletons with a lifetime equivalent to the lifetime of the the application. It seems to me you should register your service as a singleton outside of the service class itself. Something like

public class PurgeService : IHostedService
{
   // no weird constructor taking in IServiceProvider
}

Also, using an IoC inside of a class is a bit of an antipattern. Inject a DB context factory instead of trying to resolve through a container inside your class.

Upvotes: 2

Related Questions