No parameterless constructor defined for this object

Hello,

I’ve just installed Hangfire package in my MVC website. I’ve created a Startup class

[assembly: OwinStartup(typeof(Website.Startup))]

namespace Website
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            Hangfire.ConfigureHangfire(app);
            Hangfire.InitializeJobs();
        }
    }
}

and a Hangfire class

public class Hangfire
{
    public static void ConfigureHangfire(IAppBuilder app)
    {
        app.UseHangfire(config =>
        {
            config.UseSqlServerStorage("DefaultConnection");
            config.UseServer();
            config.UseAuthorizationFilters(); 
        });
    }

    public static void InitializeJobs()
    {
        RecurringJob.AddOrUpdate<CurrencyRatesJob>(j => j.Execute(), "* * * * *");
    }
}

Also, I’ve created a new job in a separate class library

public class CurrencyRatesJob
{
    private readonly IBudgetsRepository budgetsRepository;

    public CurrencyRatesJob(IBudgetsRepository budgetsRepository)
    {
        this.budgetsRepository = budgetsRepository;
    }

    public void Execute()
    {
        try
        {
            var budgets = new BudgetsDTO();
            var user = new UserDTO();

            budgets.Sum = 1;
            budgets.Name = "Hangfire";
            user.Email = "email@g.com";

            budgetsRepository.InsertBudget(budgets, user);
        }
        catch (Exception ex)
        {
            var message = ex.ToString();
            throw new NotImplementedException(message);
        }
    }
}

So when I run the application, in the Hangfire’s dashboard I get the following error:

Failed An exception occurred during job activation.
System.MissingMethodException

No parameterless constructor defined for this object.

System.MissingMethodException: No parameterless constructor defined for this object.
   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic)
   at System.Activator.CreateInstance(Type type)
   at Hangfire.JobActivator.ActivateJob(Type jobType)
   at Hangfire.Common.Job.Activate(JobActivator activator)

So, if I define a parameterless constructor in this job, I’ll lose the IBudgetRepository object, which is not good. (I tried giving it a parameterless constructor, and the job was executed, but as I was saying I didn’t have the IBudgetRepository).

I am using Ninject for DI purposes and I’ve seen that there is a Hangfire.Ninject Nuget package, but I’m not sure how to solve this issue.

Here’s some general information about using containers with Hangfire: http://docs.hangfire.io/en/latest/background-methods/using-ioc-containers.html

The Ninject GitHub site shows the usage of Njinject specifically:

Yes, I’ve read that, but I’m a little bit confused about where to put this:

var kernel = new StandardKernel();
GlobalConfiguration.Configuration.UseNinjectActivator(kernel);

If I add it to Global.asax I get a Ninject.ActivationException and if I add it to the job, right after the try, I get the same parameterless exception.

I would personally set it just before app.UseHangfire is called. I’m assuming you already have a Ninject kernel created before this point that you’ve already configured ?

Well, I have used the kernel to bind some interfaces to their classes (NinjectWebCommon class). I’ve added the code right before app.UseHangfire and I get the same Ninject.ActivationException error.

Ninject.ActivationException: Error activating IBudgetsRepository
No matching bindings are available, and the type is not self-bindable.
Activation path:
  2) Injection of dependency IBudgetsRepository into parameter budgetsRepository of constructor of type CurrencyRatesJob
  1) Request for CurrencyRatesJob

Suggestions:
  1) Ensure that you have defined a binding for IBudgetsRepository.
  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.

   at Ninject.KernelBase.Resolve(IRequest request)
   at Ninject.Planning.Targets.Target`1.GetValue(Type service, IContext parent)
   at Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent)
   at Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target)
   at Ninject.Activation.Providers.StandardProvider.<>c__DisplayClass4.<Create>b__2(ITarget target)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Ninject.Activation.Providers.StandardProvider.Create(IContext context)
   at Ninject.Activation.Context.ResolveInternal(Object scope)
   at Ninject.Activation.Context.Resolve()
   at Ninject.KernelBase.<>c__DisplayClass15.<Resolve>b__f(IBinding binding)
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
   at Ninject.ResolutionExtensions.Get(IResolutionRoot root, Type service, IParameter[] parameters)
   at Hangfire.NinjectJobActivator.ActivateJob(Type jobType)
   at Hangfire.Common.Job.Activate(JobActivator activator)

So, I’ve renamed the class where I have the Hangfire configuration, from Hangfire to HangfireConfig, because there were some conflicts when I wanted to use UseNinjectActivator.

Then I moved Hangfire.GlobalConfiguration.Configuration.UseNinjectActivator(kernel); to my NinjectWebCommon class, where I have the kernel and I use it for binding the interfaces to the appropriate classes.

Now I get another error saying that Hangfire.IGlobalConfiguration does not contain a definition of UseNinjectActivator.

If you use a IoC container (which you do) and you want to invoke services that have ctor dependencies which need to be resolved via the container, then you need to configure HF to use a custom job activator. That way, when HF runs the job it will use your container/kernel, to resolve dependencies instead of using Activator.CreateInstance, which would require default ctors.

Lucky you, as you’ve found out, someone already wrote a job activator for Ninject IoC, and released it in a nuget pkg!

see the following link for details:
http://docs.hangfire.io/en/latest/background-methods/using-ioc-containers.html?highlight=container

I would suggest that you download the Hangfire.Ninject source code and reference it locally so that you can debug it, then stick a breakpoint both where you register IBudgetsRepository and inside the ActivateJob method of the activator registered by UseNinjectActivator. Ensure that:

  1. The Ninject kernel is indeed the same instance
  2. The breakpoints are hit in the right order
  3. The kernel includes a binding for IBudgetsRepository as well as any dependencies of IBudgetsRepository
  4. Try creating an instance from the kernel in the immediate window