3

I am trying to set up a Hangfire recurrent job on application startup, but in the job if I try to use an injected IRepository, it gives an error related to the DbContext when it tries to execute a query:

System.ObjectDisposedException
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. Object name: 'WsApplicationDbContext'.

System.ObjectDisposedException: 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.
Object name: 'WsApplicationDbContext'.
   at Microsoft.EntityFrameworkCore.DbContext.CheckDisposed()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityType()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityQueryable()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Linq.IQueryable.get_Provider()
   at System.Linq.Queryable.Select[TSource,TResult](IQueryable`1 source, Expression`1 selector)
   at WsApplication.RecurringJobs.Jobs.ContainerIsBookedOffHireRecurringJob.TestJob() in C:\Projects\boxman\aspnet-core\src\WsApplication.Application\RecurringJobs\Jobs\ContainerIsBookedOffHireRecurringJob.cs:line 26

I've registered Hangfire exactly as it is described in the ABP documentation. In addition I am registering my job like this in the <ApplicationName>.Web.Core module:

public override void PostInitialize()
{
    ...

    // set up recurring background jobs
    var job = IocManager.Resolve<ContainerIsBookedOffHireRecurringJob>();
    RecurringJob.AddOrUpdate<ContainerIsBookedOffHireRecurringJob>("TestJobWithRepository", j => j.TestJob(), Cron.Daily);
}

And my job method is simply trying to do a query with an injected repository.

public class ContainerIsBookedOffHireRecurringJob : BaseRecurringJob
{
    private readonly IRepository<ContractLineMovement, int> _contractLineMovementRepository;

    public ContainerIsBookedOffHireRecurringJob(
        IIocResolver iocResolver,
        IRepository<ContractLineMovement, int> contractLineMovementRepository
    ) : base(iocResolver)
    {
        _contractLineMovementRepository = contractLineMovementRepository;
    }

    public void TestJob()
    {
        var testQuery = from contractLineMovement in _contractLineMovementRepository.GetAll()
                        select contractLineMovement;

        testQuery.ToList().ForEach(t =>
        {
            Logger.Debug("Fetched ContractLineMovement ID: " + t.Id + " Type: " + t.ContractWorkFlowEventId);
        });
    }
}

I've managed to work around it by resolving a WsApplicationDbContext directly in the BaseRecurringJob but I don't really like that solution. I don't understand why it doesn't simply work with dependency injection. Is it because I'm registering them at startup? Do I need some kind of custom Job Activator?

Any help would be much appreciated.

aaron
  • 39,695
  • 6
  • 46
  • 102
Botond Béres
  • 16,057
  • 2
  • 37
  • 50

1 Answers1

7

Add [UnitOfWork] attribute and make it a virtual method:

[UnitOfWork]
public virtual void TestJob()
{
    ...
}

See: UnitOfWork Attribute Restrictions

You can use UnitOfWork attribute for:

  • All public or public virtual methods for classes that are used over an interface (Like an application service used over a service interface).
  • All public virtual methods for self-injected classes (Like MVC Controllers and Web API Controllers).
  • All protected virtual methods.
aaron
  • 39,695
  • 6
  • 46
  • 102