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… ;-)