Search code examples
c#asp.net-mvchangfirehangfire.ninject

Error activating int No matching bindings are av


I am trying to use Hangfire to run a background job in my MVC project.

I call the Enqueue method in the constructor of my controller:

public SHQSController(IUnitOfWork uow) : base(uow)
{
    BackgroundJob.Enqueue(() => _Uow.CostRepository.Merge());
}

The _Uow.CostRepository property returns an Interface:

public ICostRepository CostRepository
{
    get
    {
       return new CostRepository(_Context, _CurrentOrganisationID);
    }
}

But the job fails in hangfire giving the following reason:

Error activating int No matching bindings are av…

I have found that if I change the code so that the job is called on the implementation of ICostRepository instead of via the interface, it works:

i.e. in my controller:

BackgroundJob.Enqueue(() => _Uow.Test());

and in my unit of work:

public void Test()
{
    new CostRepository(_Context, _CurrentOrganisationID).Merge();
}

What is going on here? Is there a way to queue a job that allows me to put my implementaion in my repository rather than my unit of work?

EDIT: I found the full error message in the HangFire.State table The full error is:

Error activating int No matching bindings are available, and the type is not self-bindable. Activation path: 2) Injection of dependency int into parameter currentOrganisationID of constructor of type CostRepository 1) Request for CostRepository Suggestions: 1) Ensure that you have defined a binding for int. 2) If the binding was defined in a module, ensure that the module has been loaded into the kernel. 3) Ensure you have not accidentally created more than one kernel. 4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name. 5) If you are using automatic module loading, ensure the search path and filters are correct.

So the problem is the CurrentOrganisationID that the CostRepository is dependent on. The CurrentOrganisationID is currently retrieved from the HttpContext and set on the unit of work, which passes it to the repository's constructor as shown in my code above.


Solution

  • I think the problem with this line:

    BackgroundJob.Enqueue(() => _Uow.CostRepository.Merge());
    

    is that Hangfire interprets this as a requirement to instantiate an implementation of ICostRepository and run its Merge method rather than instantiate an implemetation of IUow and run CostRepository.Merge() on that.

    I got around that by creating a public method on the controller:

    public void Merge(int organisationid)
    {
        _Uow.CostRepository.MergeSHQSCostsTable(organisationid);
    }
    

    and passing that to the Enqueue method:

    BackgroundJob.Enqueue(() => Merge(organisationid));
    

    The job queued by Hangfire is now SHQSController.Merge and the dependencies are now correctly resolved.

    As an aside, you might notice that I now pass the organisationid in to the method as a parameter where previously it was available within the repository. This is retrieved from the HttpContext and since this isn't available when the controller is instantiated from a background job, I had to create another private method called from the constructor so that the organisationid was wired in to the background job:

    So, instead of:

    public SHQSController(IUnitOfWork uow) : base(uow)
    {
        BackgroundJob.Enqueue(() => _Uow.CostRepository.Merge(CurrentOrganisationId));
    }
    

    I have:

    public SHQSController(IUnitOfWork uow) : base(uow)
    {
       EnqueueMerge(CurrentOrganisationID);
    }
    
    private void EnqueueMerge(int organisationid)
    {
        BackgroundJob.Enqueue(() => Merge(organisationid));
    }