I'm trying to implement a service that will run jobs based on Quartz.Net. The jobs may have dependencies like IRepository<> and the repository implementation will have a NHibernate ISession injected into it. (Quartz will be hosted in a Windows Service). Jobs are resolved via a IJob factory implementation that uses Ninject to resolve (currently wrapped in a IServiceLocator implementation).
Job Scope
I would like to be able to use Ninject to scope the ISession per Job so that there is one session created per job that may be used in multiple IRepository<>'s .
Not sure if this is possible but am wondering if anyone has experience with this?
Can I somehow use the Job context to create a Scope that is used by Kernel.InScope(???).
Quartz.Net IJobFactory:
public class JobFactory : IJobFactory
{
    readonly IServiceLocator locator;
    public JobFactory(IServiceLocator locator)
     {
         this.locator = locator;
     }
    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    {
        try
        {               
            var jobDetail = bundle.JobDetail;
            var jobType = jobDetail.JobType;
            return (IJob)locator.Resolve(jobType);
        }
        catch (Exception e)
        {
            var se = new SchedulerException("Problem instantiating class", e);
            throw se;
        }
    }
}
Ninject Bindings:
        //Service Locator
        Bind<IServiceLocator>().To<NinjectAdapter>();
        //Quartz Bindings
        Bind<IJobFactory>().To<JobFactory>();
        //NHibernate Bindings
        Bind<ISessionFactory>().ToMethod(ctx => ctx.Kernel.Get<NHibernateConfiguration>().BuildSessionFactory()).InSingletonScope();
        Bind<ISession>().ToMethod(ctx => ctx.Kernel.Get<ISessionFactory>().OpenSession());// ToDo: Figure out how to scope session
        //Repository Bindings
        Bind(typeof (IRepository<>)).To(typeof (ReadWriteRepository<>));
Main Execution:
        InitializeIoC();
        scheduler = schedulerFactory.GetScheduler();
        scheduler.JobFactory = ServiceLocator.Resolve<IJobFactory>();
        InitializeJobs();
        scheduler.Start();
Example Job:
public class TestJob3 : IJob
{
    private readonly IRepository<Customer> repo;
    private readonly IRepository<Order> orderRepo;
    public TestJob3(IRepository<Customer> repo, IRepository<Order> orderRepo)
    {
        //orderRepo and repo should have the same ISession
        this.repo = repo;
        this.oderRepo = orderRepo;
        System.Diagnostics.Debug.WriteLine("Job 3 Created");
    }
    #region Implementation of IJob
    public void Execute(IJobExecutionContext context)
    {
        System.Diagnostics.Debug.WriteLine("Job 3 Executing");
        using (var scope = new TransactionScope())
        {
            var customer = repo.GetById(1);
            customer.Name = "Blue Goats";
            repo.Save(customer);
            scope.Complete();
        }
    }
    #endregion
}
** Repository Snippet: **
public class ReadWriteRepository<TEntity> : IRepository<TEntity> where TEntity : class, IRootEntity
{
    private readonly ISession session;
    public ReadWriteRepository(ISession session)
    {
        this.session = session;
    }
    public virtual TEntity GetById(int id)
    {
        var entity = session.Get<TEntity>(id);
        return entity;
    }
    public virtual TEntity Save(TEntity entity)
    {
        session.SaveOrUpdate(entity);
        return entity;
    }
}
Thanks for taking the time!
Update I ended up using Remo's suggestion and am using InCallScope():
Bind<ISession>().ToMethod(ctx => ctx.Kernel.Get<ISessionFactory>().OpenSession()).InCallScope();
The way I like to think of it (correct or not?) is everything from the "initial" get reuses the same items throughout the dependency tree
Use InCallScope
https://github.com/ninject/ninject.extensions.namedscope/wiki/InCallScope
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With