Quartz.NET, NH ISession & Ninject Scope - PullRequest
5 голосов
/ 08 марта 2012

Я пытаюсь реализовать сервис, который будет запускать задания на основе Quartz.Net. Задания могут иметь зависимости, такие как IRepository <>, и реализация репозитория будет иметь встраиваемую сессию NHibernate. (Кварц будет размещен в службе Windows). Задания разрешаются с помощью реализации фабрики IJob, которая использует Ninject для разрешения (в настоящее время включена в реализацию IServiceLocator).

Объем работ

Я хотел бы иметь возможность использовать Ninject для определения области ISession для каждого задания, чтобы для каждого задания был создан один сеанс, который можно использовать в нескольких IRepository <>.

Не уверен, возможно ли это, но мне интересно, есть ли у кого-нибудь опыт с этим?

Могу ли я каким-либо образом использовать контекст задания для создания Scope, который используется 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<>));

Основное исполнение:

        InitializeIoC();
        scheduler = schedulerFactory.GetScheduler();
        scheduler.JobFactory = ServiceLocator.Resolve<IJobFactory>();
        InitializeJobs();
        scheduler.Start();

Пример задания:

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
}

** Фрагмент репозитория: **

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;
    }
}

Спасибо, что нашли время!

Обновление В итоге я воспользовался предложением Ремо и использую InCallScope ():

Bind<ISession>().ToMethod(ctx => ctx.Kernel.Get<ISessionFactory>().OpenSession()).InCallScope();

Мне нравится думать об этом (правильно или нет?) - все от «начального» get использует одни и те же элементы в дереве зависимостей

1 Ответ

2 голосов
/ 08 марта 2012
...