'Hangfire cannot find registered service
I have an issue with Hangfire, most likely because of my ignorance about some topics.
I have a host/plugins infrastructure, where each plugin is loaded at runtime and it register its interfaces.
public void ConfigureServices(IServiceCollection services, IConfigurationRoot Configuration)
{
services.AddTransient<IManager, Manager>();
services.AddTransient<IAnotherManager, AnotherManager>();
this.AddControllers(services);
}
Some plugin may add jobs using Hangfire, which are also set during runtime
public void ScheduleJobs()
{
RecurringJob.AddOrUpdate<IManager>(n => n.SayHello(), Cron.Monthly);
}
The issue I have is, while any service registered directly in the host is correctly resolved in hangfire, all the interfaces (ex IManager) that are defined in external assemblies aren't found.
I added a customer JobActivator where I'm passing the IServiceCollection and I can actually see that those external services are registered (and I can use them anywhere else but from Hangfire), but still in the JobActivator, when Hangfire tries to resolve the external service, it fails.
public override object ActivateJob(Type type)
{
// _serviceCollection contains the IManager service
var _provider = _serviceCollection.BuildServiceProvider();
// this will throw an Exception => No service for type '[...].IManager' has been registered.
var implementation = _provider.GetRequiredService(type);
return implementation;
}
In the same example, if I use the Default JobActivator, then the exception I get is System.MissingMethodException: Cannot create an instance of an interface.
I could enqueue the job using the Class instead of the Interface, but that's not the point and anyway if the Class has services injected, those will not be resolved as well.
What am I missing?
Solution 1:[1]
The problem has been solved. The solution is to add a specific IoC Container for hangfire. I used Unity. In that way dependencies are resolved correctly.
Solution 2:[2]
Thanks Matteo for making it clear that HF requires its own IoC container. This link makes the point too:
Hangfire needs to have it's own container with dependencies registered independently of the global UnityContainer. The reason for this is twofold; Hangfire's dependencies need to be registered with the PerResolveLifetimeManager lifetime manager. This is so that you don't get concurrency issues between workers that have resolved a dependency to the same instance. For example; with the normal HierarchicalLifetimeManager, two workers needing the same repository dependency may resolve to the same instance and share a common db context. The workers are meant to each have their own db contexts. Secondly, when the OWIN bootstrapper is run, the global UnityContainer may or may not be initialised yet and Hangfire is unable to take in a reference to the container. So giving Hangfire it's own managed container is a clear separation of purpose and behaviour in how our dependencies are resolved.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Matteo Alvazzi Delfrate |
| Solution 2 | majjam |
