You're almost there. You need to create the following hybrid lifestyle:
var hybridLifestyle = Lifestyle.CreateHybrid(
container.GetCurrentWcfOperationScope() != null,
new WcfOperationLifestyle(),
new LifetimeScopeLifestyle());
You need to call either container.GetCurrentWcfOperationScope()
or container.GetCurrentLifetimeScope()
to determine which lifestyle to select.
Furthermore, you should absolutely prevent from needing to reference the Container
in your MyJob
(or any job implementation). That's an anti-pattern. Instead you should create a IJob
decorator that adds lifetime scoping behavior to a job:
// This class is part of your Composition Root
public class LifetimeScopeJobDecorator : IJob {
private readonly IJob _decoratee;
private readonly Container _container;
public LifetimeScopeJobDecorator(IJob decoratee, Container container) {
_decoratee = decoratee;
_container = container;
}
public void Execute(IJobExecutionContext context) {
using (_container.BeginLifetimeScope()) {
_decoratee.Execute(context);
}
}
}
Now there are two ways to apply decorator to the jobs that the SimpleInjectorJobFactory
returns. The easiest way is to add the decorator manually inside the SimpleInjectorJobFactory.NewJob
method:
var job = (IJob)_container.GetInstance(jobType);
return new LifetimeScopeJobDecorator(job, _container);
Much prettier would it be to let Simple Injector do the decoration for you, but that would be a more code in your case. Here's the way to do it:
Type[] jobTypes = /* fetch IJob implementations here */;
// Instead of calling jobTypes.ToList().ForEach(container.Register), we register the
// types as a collection of IJob types.
container.RegisterAll<IJob>(types);
// Here we register the decorator
container.RegisterDecorator(typeof(IJob), typeof(LifetimeScopeJobDecorator));
// We create a jobFactory delegate.
// we use Lazy<T> because at this stage in the application the container might not
// be fully initialized yet.
var jobs = new Lazy<IEnumerable<IJob>>(() => container.GetAllInstance<IJob>());
var jobIndexes = types.ToDictionary(t => t, t => types.IndexOf(t));
Func<Type, IJob> jobFactory = jobType => jobs.Value.ElementAt(jobIndexes[jobType]);
// And pass that job factory on to the SimpleInjectorJobFactory.
var factory = new SimpleInjectorJobFactory(jobFactory);
// Inside the SimpleInjectorJobFactory:
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
// ...
// replace "return (IJob)_container.GetInstance(jobType);" with:
return _jobFactory(jobType);
// ...
}
This last solution is more complex, but this method gets really interesting when you have multiple decorators, especially if they need to be applied conditionally based on the implementation type. This way the factory doesn't need to know anything about the applied decorators.