Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Quartz.NET, NH ISession & Ninject Scope

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

like image 430
Mike Rowley Avatar asked Nov 05 '22 04:11

Mike Rowley


1 Answers

Use InCallScope

https://github.com/ninject/ninject.extensions.namedscope/wiki/InCallScope

like image 67
Remo Gloor Avatar answered Nov 09 '22 15:11

Remo Gloor