2

My project structure is same as :

https://github.com/MarlabsInc/webapi-angularjs-spa

I have followed the instructions in :

http://docs.hangfire.io/en/latest/background-methods/using-ioc-containers.html

So I have created a container job activator.

In my Bootstrapper.cs

containerBuilder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>().AsImplementedInterfaces().InstancePerApiRequest();
containerBuilder.RegisterType<UnitOfWork>().As<IUnitOfWork>().AsImplementedInterfaces().InstancePerApiRequest();
containerBuilder.RegisterApiControllers(System.Reflection.Assembly.GetExecutingAssembly());
IContainer container = containerBuilder.Build();

Hangfire.GlobalConfiguration.Configuration
.UseAutofacActivator(container);
JobActivator.Current = new AutofacJobActivator(container);
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);

My startup class has a method :

GlobalConfiguration.Configuration
.UseSqlServerStorage("entitiesDB",
new SqlServerStorageOptions
{
    PrepareSchemaIfNecessary = false,
    InvisibilityTimeout = TimeSpan.FromMinutes(30)
});

app.UseHangfireDashboard();
app.UseHangfireServer();

In controller : I am trying to update the status of 2000 invoices as "Approved" So the method is straightforward as follows :

foreach(int id in invoiceIds)
{
   BackgroundJob.Enqueue<IInvoiceService>(a => a.UpdateInvoice(id));
}

Now when I query in the SQL :

 select * from HangFire.[State]

I get the following exception in Data column:

{"FailedAt":"2015-07-07T10:00:40.9454943Z","ExceptionType":"Autofac.Core.DependencyResolutionException","ExceptionMessage":"No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.","ExceptionDetails":"Autofac.Core.DependencyResolutionException: No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.\r\n at Autofac.Core.Lifetime.MatchingScopeLifetime.FindScope(ISharingLifetimeScope mostNestedVisibleScope)\r\n at Autofac.Core.Resolving.InstanceLookup..ctor(IComponentRegistration registration, IResolveOperation context, ISharingLifetimeScope mostNestedVisibleScope, IEnumerable1 parameters)\r\n at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable1 parameters)\r\n at Autofac.Core.Resolving.ResolveOperation.ResolveComponent(IComponentRegistration registration, IEnumerable1 parameters)\r\n at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable1 parameters)\r\n at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable1 parameters)\r\n at Autofac.Core.Container.ResolveComponent(IComponentRegistration registration, IEnumerable1 parameters)\r\n at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable1 parameters, Object& instance)\r\n at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable1 parameters)\r\n at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType, IEnumerable`1 parameters)\r\n at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType)\r\n at Hangfire.AutofacJobActivator.ActivateJob(Type jobType)\r\n at Hangfire.Common.Job.Activate(JobActivator activator)"}

Can someone please help me understand what I am doing wrong ?

Jerry
  • 1,762
  • 5
  • 28
  • 42
user3825003
  • 191
  • 1
  • 5
  • 12

1 Answers1

4

You are using InstancePerApiRequest so your IoC container knows to create a new instance for each API request.

But, your background job is not executing inside an API request, so your IoC container does not know how to resolve your dependencies.

From the hangfire docs:

HttpContext is not available

Request information is not available during the instantiation of a target type. If you register your dependencies in a request scope (InstancePerHttpRequest in Autofac, InRequestScope in Ninject and so on), an exception will be thrown during the job activation process.

So, the entire dependency graph should be available. Either register additional services without using the request scope, or use separate instance of container if your IoC container does not support dependency registrations for multiple scopes.

According to this related SO question, Autofac does not support registering for multiple scopes out of the box so you will need to either:

  1. Use a "lower" scope such as "InstancePerDependency", or
  2. Use a separate IoC container for background jobs.

UPDATE:

The Hangfire Autofac integration package introduces a InstancePerBackgroundJob() extension method, and suggests that Autofac does support registering for multiple scopes like this:

builder.RegisterType<Database>()
       .InstancePerBackgroundJob()
       .InstancePerHttpRequest();

However, it's only available in the 1.2.0-beta1 release of Hangfire.Autofac which requires Hangfire 1.5.0-beta1.

Community
  • 1
  • 1
Ergwun
  • 12,579
  • 7
  • 56
  • 83
  • Hi Ergwun, thanks for your reply. I have tried using InstancePerDependency, still it didn't work. For one thing I have tried SingleInstance, it worked for one time, but the rest of the enqueued items were never processed. I also tried creating a seperate IOC container, even that didn't work. Is there something I am missing ? – user3825003 Aug 24 '15 at 05:27
  • I'm just in the process of trying to get it working myself. I'll keep you posted. In the meantime, you could try out the new `InstancePerBackgroundJob()` in the latest beta version of Hangfire.Autofac (+Hangfire) - see my update. Which scope did you use when using a seperate IOC container? What were the errors you got in the other configurations you tried? – Ergwun Aug 24 '15 at 12:48
  • Hi Ergwun, I have kept it on hold, we are thinking of implementing our own framework to do that. But hangfire was a far better option. Its like we are re-inventing the wheel. So did you get it to work ? – user3825003 Oct 07 '15 at 07:12
  • @user3825003 Unfortunately I've had to put it on hold myself. Hoping to get back to it in about a week or so. – Ergwun Oct 08 '15 at 02:51
  • Ever get this working? "InstancePerBackgroundJob()" simply does not seem to work....can't seem to open up an issue on GitHub either.. – cjones26 Oct 27 '15 at 15:51
  • @Ergwun I am having that exact same problem. Have you guys found any solution to this? Thanks! I will keep looking myself and eventually post it here. – John Nov 16 '15 at 10:54
  • 1
    @slashp I haven't returned to this yet in my work, but I did have another go to get a minimal example working now that it's out of beta, but without any success. When I get another chance I'll put it on github and try and raise a issue with the project. – Ergwun Dec 02 '15 at 00:36
  • @John See my comment above. – Ergwun Dec 02 '15 at 00:48
  • @Ergwun, thanks! I will keep an eye on this question. Glad I am not the only one who can't seem to get this working. – cjones26 Dec 02 '15 at 12:03