If you have ever tried to use Quartz.NET (a famous job-scheduling library) with Castle Windsor (IoC/DI container) you might need to register a component whose life-style should be bound to the job itself (LifestylePerJob). There are plenty of alternatives available which all have the same characteristics – they do not work:
- LifestylePerThread – does not reset the thread when running a new job
- BoundTo<Job>() – does not support typed factories when resolved inside the job
- BoundTo<object>() – does not support typed factories when resolved inside the job
- Quartz.IJobFactory + LifestyleScoped – does not support typed factories when resolved into the job (the scope from JobFactory is not propagated inside the job!)
There is a “simple” workaround for such scenarios. You can use LifestyleScoped but you have to begin/end the scope in the job.
If you use the job itself just as a plumbing class where the work itself is encapsulated in a separate service (and you should do this) then you can simply inject both a service-factory and the kernel and then do the scope-work in the job itself:
public class MyJob : IJob
{
private readonly IServiceFactory<MyService> myServiceFactory;
private readonly IKernel kernel;
public MyJob(IServiceFactory<MyService> myServiceFactory, IKernel kernel)
{
this.myServiceFactory = myServiceFactory;
this.kernel = kernel;
}
public void Execute()
{
using (var scope = kernel.BeginScope())
{
// use your way to work with factories ;-)
using (var myService = myServiceFactory.Create())
{
myService.DoWork();
}
// BTW: we have an extension method
myServiceFactory.ExecuteAction(service => service.DoWork());
}
}
}
…the MyService class has all the dependencies you need and as you use it using the factory it behaves as the pseudo-resolution-root for this scenario. You might use the kernel.Resolve+Release in the job but I always prefer not to… ;-)