2

In my solution, I use EF with repository pattern and Ninject inside my main web project to resolve controller dependencies, I also have a Job project that manages Quartz jobs - what is the proper way to link Ninject with Quartz so that EF will work?

I know I need to implement custom JobFactory, so I created the following in my Job project:

public class NinjectJobFactory : IJobFactory
{
    private readonly IKernel resolutionRoot;

    public NinjectJobFactory(IKernel resolutionRoot)
    {
        this.resolutionRoot = resolutionRoot;
    }

    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    {
        return (IJob)this.resolutionRoot.Get(bundle.JobDetail.JobType);
    }

    public void ReturnJob(IJob job)
    {
        string dud = "";
    }
}

And in order to initialize quartz Jobs I do the following:

  1. Inside Global.asax: I first initialize my NinjectResolver, and then pass the NinjectKernel to JobManager class, as a parameter.
  2. Then inside JobManager, I add jobs and runs the scheduler like this:

    public void Start()
    {
        ISchedulerFactory sf = new StdSchedulerFactory();
        IScheduler sched = sf.GetScheduler();
        sf.GetScheduler().JobFactory = new NinjectJobFactory(ninjectKernel);
    
        DateTimeOffset runTime = DateBuilder.EvenMinuteDate(DateTime.UtcNow);
        DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(null, 10);
    
        IJobDetail job = JobBuilder.Create<CheckIfAllSaleActionDataIsValid>()
     .WithIdentity("CheckIfAllSaleActionDataIsValid", "HostessStatJobs")
    .Build();
    
    job.JobDataMap.Add("SiteUrl", SiteUrl);
    
    ITrigger trigger = TriggerBuilder.Create()
    .WithIdentity("CheckIfAllSaleActionDataIsValidTrigger", "HostessStatJobTriggers")
    .StartAt(startTime)
    .WithCronSchedule("0 0 0/1 1/1 * ? *")
    .Build();
    
    sched.ScheduleJob(job, trigger);
    
    IJobDetail job2 = JobBuilder.Create<CheckPaymentAndAssigneRoles>()
    .WithIdentity("CheckPaymentAndAssigneRoles", "HostessStatJobs")
    .Build();
    
    job2.JobDataMap.Add("commonMethods", ninjectKernel.Get<CommonMethods>());
    
    ITrigger trigger2 = TriggerBuilder.Create()
    .WithIdentity("CheckPaymentAndAssigneRolesTrigger", "HostessStatJobTriggers")
    .StartAt(startTime)
    .WithCronSchedule("0 0/1 * 1/1 * ? *")
    .Build();
    
         sched.ScheduleJob(job2, trigger2);
    
         sched.Start();
     }
    

Problem is that DbContext of each object generated by NinjectJobFactory is different, and I cannot use EF because of this (I get: An entity object cannot be referenced by multiple instances of IEntityChangeTracker which is understandable since each object in my repository has reference to different DbContext).

Weird part is that - If I manually call NinjectKernel.Get(); - for example - inside Global.asax I can clearly see that single context is passed - as it should be.

My context is binded in my Ninjectresolver like this: ninjectKernel.Bind().ToSelf().InRequestScope(); - can this be the problem?

Questions are:

  1. What am I doing wrong?
  2. If this is because I pass my NinjectKernel around - would creating different NinjectResolver inside my Job project help?
  3. If AD2 is true - is it advisable to create different IoC for each project, or should we do it only when really necessary ?

EDIT:

Sorry for the late response, It would appear that InRequestScope was in fact the problem - I have created separate ninject kernel inside my QuartzJobs sub-project, and:

  1. When I use InTransientScope - I got the same behaviour as before, that is: different DbContext for every object.
  2. When I use InSingletonScope or InThreadScope - it works, I got single DbContext for every object, however - DbContext does not change every time job starts.

Question is - won't it break my database? As I understand, it is recommended to use new DbContext for each user request to avoid database deadlocks - correct me if I am wrong, but it is not necessary for a Quartz job project? I mean - this project will always use single connection, so it shouldn't deadlock the database?

Am I correct? If not - what is the correct way to inject different DbContext every time Job is run? InRequestScope will not work outside MVC project...

user2384366
  • 1,034
  • 2
  • 12
  • 28
  • Well which `DbContext`instance should the Job use? As quartz schedules jobs at a later point, there is no "valid" request at that point. So i guess that binding `DbContext` `.InRequestScope()` does not work properly. You need some other way to control the lifecycle of `DbContext` for scheduled jobs. – BatteryBackupUnit Apr 30 '14 at 10:02
  • @BatteryBackupUnit: Sorry for my late response - please see my edit. – user2384366 May 05 '14 at 06:23

0 Answers0